From 306a06e5f766acaf26b71397a5692c65b65a61c7 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Fri, 23 Jun 2017 17:24:00 +0100 Subject: [PATCH 01/85] block: expose crypto option names / defs to other drivers The block/crypto.c defines a set of QemuOpts that provide parameters for encryption. This will also be needed by the qcow/qcow2 integration, so expose the relevant pieces in a new block/crypto.h header. Some helper methods taking QemuOpts are changed to take QDict to simplify usage in other places. Reviewed-by: Max Reitz Reviewed-by: Eric Blake Reviewed-by: Alberto Garcia Signed-off-by: Daniel P. Berrange Message-id: 20170623162419.26068-2-berrange@redhat.com Signed-off-by: Max Reitz --- block/crypto.c | 82 +++++++++++++++------------------------------ block/crypto.h | 91 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 117 insertions(+), 56 deletions(-) create mode 100644 block/crypto.h diff --git a/block/crypto.c b/block/crypto.c index 10e5ddccaa..ea40ba49b8 100644 --- a/block/crypto.c +++ b/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) { @@ -240,9 +202,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 +214,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) { @@ -299,6 +261,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 +276,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; } @@ -337,6 +302,7 @@ static int block_crypto_open_generic(QCryptoBlockFormat format, ret = 0; cleanup: + QDECREF(cryptoopts); qapi_free_QCryptoBlockOpenOptions(open_opts); return ret; } @@ -356,8 +322,11 @@ 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; } @@ -375,6 +344,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); diff --git a/block/crypto.h b/block/crypto.h new file mode 100644 index 0000000000..c0e9b549aa --- /dev/null +++ b/block/crypto.h @@ -0,0 +1,91 @@ +/* + * 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 . + * + */ + +#ifndef BLOCK_CRYPTO_H__ +#define BLOCK_CRYPTO_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" + +#define BLOCK_CRYPTO_OPT_DEF_LUKS_KEY_SECRET \ + { \ + .name = BLOCK_CRYPTO_OPT_LUKS_KEY_SECRET, \ + .type = QEMU_OPT_STRING, \ + .help = "ID of the secret that provides the keyslot passphrase", \ + } + +#define BLOCK_CRYPTO_OPT_DEF_LUKS_CIPHER_ALG \ + { \ + .name = BLOCK_CRYPTO_OPT_LUKS_CIPHER_ALG, \ + .type = QEMU_OPT_STRING, \ + .help = "Name of encryption cipher algorithm", \ + } + +#define BLOCK_CRYPTO_OPT_DEF_LUKS_CIPHER_MODE \ + { \ + .name = BLOCK_CRYPTO_OPT_LUKS_CIPHER_MODE, \ + .type = QEMU_OPT_STRING, \ + .help = "Name of encryption cipher mode", \ + } + +#define BLOCK_CRYPTO_OPT_DEF_LUKS_IVGEN_ALG \ + { \ + .name = 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 \ + { \ + .name = 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 \ + { \ + .name = BLOCK_CRYPTO_OPT_LUKS_HASH_ALG, \ + .type = QEMU_OPT_STRING, \ + .help = "Name of encryption hash algorithm", \ + } + +#define BLOCK_CRYPTO_OPT_DEF_LUKS_ITER_TIME \ + { \ + .name = 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__ */ From 4a47f85431aa6bed22157f683196affe8b06c69e Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Fri, 23 Jun 2017 17:24:01 +0100 Subject: [PATCH 02/85] block: add ability to set a prefix for opt names When integrating the crypto support with qcow/qcow2, we don't want to use the bare LUKS option names "hash-alg", "key-secret", etc. We need to namespace them to match the nested QAPI schema. e.g. "encrypt.hash-alg", "encrypt.key-secret" so that they don't clash with any general qcow options at a later date. Reviewed-by: Eric Blake Reviewed-by: Max Reitz Reviewed-by: Alberto Garcia Signed-off-by: Daniel P. Berrange Message-id: 20170623162419.26068-3-berrange@redhat.com Signed-off-by: Max Reitz --- block/crypto.c | 16 ++++++++-------- block/crypto.h | 40 ++++++++++++++++++++-------------------- 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/block/crypto.c b/block/crypto.c index ea40ba49b8..9df1e5dde2 100644 --- a/block/crypto.c +++ b/block/crypto.c @@ -129,7 +129,7 @@ static QemuOptsList block_crypto_runtime_opts_luks = { .name = "crypto", .head = QTAILQ_HEAD_INITIALIZER(block_crypto_runtime_opts_luks.head), .desc = { - BLOCK_CRYPTO_OPT_DEF_LUKS_KEY_SECRET, + BLOCK_CRYPTO_OPT_DEF_LUKS_KEY_SECRET(""), { /* end of list */ } }, }; @@ -144,13 +144,13 @@ static QemuOptsList block_crypto_create_opts_luks = { .type = QEMU_OPT_SIZE, .help = "Virtual disk size" }, - 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, + 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 */ } }, }; diff --git a/block/crypto.h b/block/crypto.h index c0e9b549aa..3430dcd50c 100644 --- a/block/crypto.h +++ b/block/crypto.h @@ -29,51 +29,51 @@ #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 \ +#define BLOCK_CRYPTO_OPT_DEF_LUKS_KEY_SECRET(prefix) \ { \ - .name = BLOCK_CRYPTO_OPT_LUKS_KEY_SECRET, \ + .name = prefix BLOCK_CRYPTO_OPT_LUKS_KEY_SECRET, \ .type = QEMU_OPT_STRING, \ .help = "ID of the secret that provides the keyslot passphrase", \ } -#define BLOCK_CRYPTO_OPT_DEF_LUKS_CIPHER_ALG \ +#define BLOCK_CRYPTO_OPT_DEF_LUKS_CIPHER_ALG(prefix) \ { \ - .name = BLOCK_CRYPTO_OPT_LUKS_CIPHER_ALG, \ + .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 \ - { \ - .name = BLOCK_CRYPTO_OPT_LUKS_CIPHER_MODE, \ - .type = QEMU_OPT_STRING, \ - .help = "Name of encryption cipher mode", \ +#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 \ - { \ - .name = BLOCK_CRYPTO_OPT_LUKS_IVGEN_ALG, \ - .type = QEMU_OPT_STRING, \ - .help = "Name of IV generator algorithm", \ +#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 \ +#define BLOCK_CRYPTO_OPT_DEF_LUKS_IVGEN_HASH_ALG(prefix) \ { \ - .name = BLOCK_CRYPTO_OPT_LUKS_IVGEN_HASH_ALG, \ + .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 \ +#define BLOCK_CRYPTO_OPT_DEF_LUKS_HASH_ALG(prefix) \ { \ - .name = BLOCK_CRYPTO_OPT_LUKS_HASH_ALG, \ + .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 \ +#define BLOCK_CRYPTO_OPT_DEF_LUKS_ITER_TIME(prefix) \ { \ - .name = BLOCK_CRYPTO_OPT_LUKS_ITER_TIME, \ + .name = prefix BLOCK_CRYPTO_OPT_LUKS_ITER_TIME, \ .type = QEMU_OPT_NUMBER, \ .help = "Time to spend in PBKDF in milliseconds", \ } From 0b4ee9090e278a46b00b21624ba610552d0106d8 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Fri, 23 Jun 2017 17:24:02 +0100 Subject: [PATCH 03/85] qcow: document another weakness of qcow AES encryption Document that use of guest virtual sector numbers as the basis for the initialization vectors is a potential weakness, when combined with internal snapshots or multiple images using the same passphrase. This fixes the formatting of the itemized list too. Reviewed-by: Max Reitz Reviewed-by: Alberto Garcia Signed-off-by: Daniel P. Berrange Message-id: 20170623162419.26068-4-berrange@redhat.com Signed-off-by: Max Reitz --- qemu-img.texi | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/qemu-img.texi b/qemu-img.texi index 5b925ecf41..f335139217 100644 --- a/qemu-img.texi +++ b/qemu-img.texi @@ -567,16 +567,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 From 6aa837f7bd60903573e0644f503f455454bbf5ae Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Fri, 23 Jun 2017 17:24:03 +0100 Subject: [PATCH 04/85] qcow: require image size to be > 1 for new images The qcow driver refuses to open images which are less than 2 bytes in size, but will happily create such images. Add a check in the create path to avoid this discrepancy. Reviewed-by: Max Reitz Reviewed-by: Alberto Garcia Reviewed-by: Eric Blake Signed-off-by: Daniel P. Berrange Message-id: 20170623162419.26068-5-berrange@redhat.com Signed-off-by: Max Reitz --- block/qcow.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/block/qcow.c b/block/qcow.c index 7bd94dcd46..49871fb873 100644 --- a/block/qcow.c +++ b/block/qcow.c @@ -811,6 +811,12 @@ static int qcow_create(const char *filename, QemuOpts *opts, Error **errp) /* 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; From ebab5636f99eda7034984c27fc30d2c50912bf1c Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Fri, 23 Jun 2017 17:24:04 +0100 Subject: [PATCH 05/85] iotests: skip 042 with qcow which dosn't support zero sized images Test 042 is designed to verify operation with zero sized images. Such images are not supported with qcow (v1), so this test has always failed. Reviewed-by: Max Reitz Reviewed-by: Alberto Garcia Signed-off-by: Daniel P. Berrange Message-id: 20170623162419.26068-6-berrange@redhat.com Signed-off-by: Max Reitz --- tests/qemu-iotests/042 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/qemu-iotests/042 b/tests/qemu-iotests/042 index 351b2830a2..a53e7cb757 100755 --- a/tests/qemu-iotests/042 +++ b/tests/qemu-iotests/042 @@ -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 From 06af39ecf9da95bbd6dd38e86b15dbc042a6e09c Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Fri, 23 Jun 2017 17:24:05 +0100 Subject: [PATCH 06/85] iotests: skip 048 with qcow which doesn't support resize Test 048 is designed to verify data preservation during an image resize. The qcow (v1) format impl has never supported resize so always fails. Reviewed-by: Max Reitz Reviewed-by: Alberto Garcia Signed-off-by: Daniel P. Berrange Message-id: 20170623162419.26068-7-berrange@redhat.com Signed-off-by: Max Reitz --- tests/qemu-iotests/048 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/qemu-iotests/048 b/tests/qemu-iotests/048 index 203c04fc7f..9ed04a068d 100755 --- a/tests/qemu-iotests/048 +++ b/tests/qemu-iotests/048 @@ -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 From 0cb8d47ba94c0e16f22e3e385dc7c60aea852eee Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Fri, 23 Jun 2017 17:24:06 +0100 Subject: [PATCH 07/85] block: deprecate "encryption=on" in favor of "encrypt.format=aes" Historically the qcow & qcow2 image formats supported a property "encryption=on" to enable their built-in AES encryption. We'll soon be supporting LUKS for qcow2, so need a more general purpose way to enable encryption, with a choice of formats. This introduces an "encrypt.format" option, which will later be joined by a number of other "encrypt.XXX" options. The use of a "encrypt." prefix instead of "encrypt-" is done to facilitate mapping to a nested QAPI schema at later date. e.g. the preferred syntax is now qemu-img create -f qcow2 -o encrypt.format=aes demo.qcow2 Signed-off-by: Daniel P. Berrange Message-id: 20170623162419.26068-8-berrange@redhat.com Reviewed-by: Alberto Garcia Signed-off-by: Max Reitz --- block/qcow.c | 31 +++++++++--- block/qcow2.c | 34 ++++++++++--- include/block/block_int.h | 2 +- qemu-img.c | 4 +- tests/qemu-iotests/049.out | 98 +++++++++++++++++++------------------- tests/qemu-iotests/082.out | 95 +++++++++++++++++++++++------------- tests/qemu-iotests/085.out | 38 +++++++-------- tests/qemu-iotests/144.out | 4 +- tests/qemu-iotests/185.out | 8 ++-- 9 files changed, 191 insertions(+), 123 deletions(-) diff --git a/block/qcow.c b/block/qcow.c index 49871fb873..a442ed73d7 100644 --- a/block/qcow.c +++ b/block/qcow.c @@ -803,10 +803,10 @@ 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; /* Read out options */ total_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0), @@ -818,8 +818,16 @@ static int qcow_create(const char *filename, QemuOpts *opts, Error **errp) } 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); @@ -873,7 +881,13 @@ 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) { + 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); } else { header.crypt_method = cpu_to_be32(QCOW_CRYPT_NONE); @@ -1047,8 +1061,13 @@ 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'", }, { /* end of list */ } } diff --git a/block/qcow2.c b/block/qcow2.c index 2f94f0326e..8f1822c195 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -2144,7 +2144,7 @@ static int qcow2_create2(const char *filename, int64_t total_size, const char *backing_file, const char *backing_format, int flags, size_t cluster_size, PreallocMode prealloc, QemuOpts *opts, int version, int refcount_order, - Error **errp) + const char *encryptfmt, Error **errp) { int cluster_bits; QDict *options; @@ -2273,7 +2273,13 @@ static int qcow2_create2(const char *filename, int64_t total_size, .header_length = cpu_to_be32(sizeof(*header)), }; - if (flags & BLOCK_FLAG_ENCRYPT) { + if (encryptfmt) { + if (!g_str_equal(encryptfmt, "aes")) { + error_setg(errp, "Unknown encryption format '%s', expected 'aes'", + encryptfmt); + ret = -EINVAL; + goto out; + } header->crypt_method = cpu_to_be32(QCOW_CRYPT_AES); } else { header->crypt_method = cpu_to_be32(QCOW_CRYPT_NONE); @@ -2402,6 +2408,7 @@ static int qcow2_create(const char *filename, QemuOpts *opts, Error **errp) int version = 3; uint64_t refcount_bits = 16; int refcount_order; + const char *encryptfmt = NULL; Error *local_err = NULL; int ret; @@ -2410,8 +2417,16 @@ static int qcow2_create(const char *filename, QemuOpts *opts, Error **errp) BDRV_SECTOR_SIZE); backing_file = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FILE); backing_fmt = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FMT); - 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_del(opts, BLOCK_OPT_ENCRYPT)) { + error_setg(errp, "Options " BLOCK_OPT_ENCRYPT " and " + BLOCK_OPT_ENCRYPT_FORMAT " are mutually exclusive"); + ret = -EINVAL; + goto finish; + } + } else if (qemu_opt_get_bool_del(opts, BLOCK_OPT_ENCRYPT, false)) { + encryptfmt = "aes"; } cluster_size = qemu_opt_get_size_del(opts, BLOCK_OPT_CLUSTER_SIZE, DEFAULT_CLUSTER_SIZE); @@ -2477,7 +2492,7 @@ static int qcow2_create(const char *filename, QemuOpts *opts, Error **errp) ret = qcow2_create2(filename, size, backing_file, backing_fmt, flags, cluster_size, prealloc, opts, version, refcount_order, - &local_err); + encryptfmt, &local_err); error_propagate(errp, local_err); finish: @@ -3431,8 +3446,13 @@ static QemuOptsList qcow2_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'", }, { .name = BLOCK_OPT_CLUSTER_SIZE, diff --git a/include/block/block_int.h b/include/block/block_int.h index 15fa602150..701508d35f 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -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" diff --git a/qemu-img.c b/qemu-img.c index f7ffb79db6..ae4fe6d83a 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -2264,6 +2264,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 +2275,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; diff --git a/tests/qemu-iotests/049.out b/tests/qemu-iotests/049.out index 34e66db691..50e91c8610 100644 --- a/tests/qemu-iotests/049.out +++ b/tests/qemu-iotests/049.out @@ -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,62 +128,62 @@ 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 == @@ -196,16 +196,16 @@ Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=on cluster_siz == 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 diff --git a/tests/qemu-iotests/082.out b/tests/qemu-iotests/082.out index a952330ba5..621386bf70 100644 --- a/tests/qemu-iotests/082.out +++ b/tests/qemu-iotests/082.out @@ -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,8 @@ 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' cluster_size qcow2 cluster size preallocation Preallocation mode (allowed values: off, metadata, falloc, full) lazy_refcounts Postpone refcount updates @@ -61,7 +62,8 @@ 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' cluster_size qcow2 cluster size preallocation Preallocation mode (allowed values: off, metadata, falloc, full) lazy_refcounts Postpone refcount updates @@ -74,7 +76,8 @@ 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' cluster_size qcow2 cluster size preallocation Preallocation mode (allowed values: off, metadata, falloc, full) lazy_refcounts Postpone refcount updates @@ -87,7 +90,8 @@ 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' cluster_size qcow2 cluster size preallocation Preallocation mode (allowed values: off, metadata, falloc, full) lazy_refcounts Postpone refcount updates @@ -100,7 +104,8 @@ 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' cluster_size qcow2 cluster size preallocation Preallocation mode (allowed values: off, metadata, falloc, full) lazy_refcounts Postpone refcount updates @@ -113,7 +118,8 @@ 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' cluster_size qcow2 cluster size preallocation Preallocation mode (allowed values: off, metadata, falloc, full) lazy_refcounts Postpone refcount updates @@ -126,7 +132,8 @@ 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' cluster_size qcow2 cluster size preallocation Preallocation mode (allowed values: off, metadata, falloc, full) lazy_refcounts Postpone refcount updates @@ -139,7 +146,8 @@ 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' cluster_size qcow2 cluster size preallocation Preallocation mode (allowed values: off, metadata, falloc, full) lazy_refcounts Postpone refcount updates @@ -147,10 +155,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 +175,8 @@ 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' cluster_size qcow2 cluster size preallocation Preallocation mode (allowed values: off, metadata, falloc, full) lazy_refcounts Postpone refcount updates @@ -180,7 +189,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 +238,8 @@ 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' cluster_size qcow2 cluster size preallocation Preallocation mode (allowed values: off, metadata, falloc, full) lazy_refcounts Postpone refcount updates @@ -242,7 +252,8 @@ 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' cluster_size qcow2 cluster size preallocation Preallocation mode (allowed values: off, metadata, falloc, full) lazy_refcounts Postpone refcount updates @@ -255,7 +266,8 @@ 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' cluster_size qcow2 cluster size preallocation Preallocation mode (allowed values: off, metadata, falloc, full) lazy_refcounts Postpone refcount updates @@ -268,7 +280,8 @@ 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' cluster_size qcow2 cluster size preallocation Preallocation mode (allowed values: off, metadata, falloc, full) lazy_refcounts Postpone refcount updates @@ -281,7 +294,8 @@ 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' cluster_size qcow2 cluster size preallocation Preallocation mode (allowed values: off, metadata, falloc, full) lazy_refcounts Postpone refcount updates @@ -294,7 +308,8 @@ 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' cluster_size qcow2 cluster size preallocation Preallocation mode (allowed values: off, metadata, falloc, full) lazy_refcounts Postpone refcount updates @@ -307,7 +322,8 @@ 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' cluster_size qcow2 cluster size preallocation Preallocation mode (allowed values: off, metadata, falloc, full) lazy_refcounts Postpone refcount updates @@ -320,7 +336,8 @@ 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' cluster_size qcow2 cluster size preallocation Preallocation mode (allowed values: off, metadata, falloc, full) lazy_refcounts Postpone refcount updates @@ -348,7 +365,8 @@ 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' cluster_size qcow2 cluster size preallocation Preallocation mode (allowed values: off, metadata, falloc, full) lazy_refcounts Postpone refcount updates @@ -407,7 +425,8 @@ 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' cluster_size qcow2 cluster size preallocation Preallocation mode (allowed values: off, metadata, falloc, full) lazy_refcounts Postpone refcount updates @@ -420,7 +439,8 @@ 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' cluster_size qcow2 cluster size preallocation Preallocation mode (allowed values: off, metadata, falloc, full) lazy_refcounts Postpone refcount updates @@ -433,7 +453,8 @@ 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' cluster_size qcow2 cluster size preallocation Preallocation mode (allowed values: off, metadata, falloc, full) lazy_refcounts Postpone refcount updates @@ -446,7 +467,8 @@ 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' cluster_size qcow2 cluster size preallocation Preallocation mode (allowed values: off, metadata, falloc, full) lazy_refcounts Postpone refcount updates @@ -459,7 +481,8 @@ 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' cluster_size qcow2 cluster size preallocation Preallocation mode (allowed values: off, metadata, falloc, full) lazy_refcounts Postpone refcount updates @@ -472,7 +495,8 @@ 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' cluster_size qcow2 cluster size preallocation Preallocation mode (allowed values: off, metadata, falloc, full) lazy_refcounts Postpone refcount updates @@ -485,7 +509,8 @@ 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' cluster_size qcow2 cluster size preallocation Preallocation mode (allowed values: off, metadata, falloc, full) lazy_refcounts Postpone refcount updates @@ -498,7 +523,8 @@ 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' cluster_size qcow2 cluster size preallocation Preallocation mode (allowed values: off, metadata, falloc, full) lazy_refcounts Postpone refcount updates @@ -528,7 +554,8 @@ 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' cluster_size qcow2 cluster size preallocation Preallocation mode (allowed values: off, metadata, falloc, full) lazy_refcounts Postpone refcount updates diff --git a/tests/qemu-iotests/085.out b/tests/qemu-iotests/085.out index a5d4cc3494..6edf107f55 100644 --- a/tests/qemu-iotests/085.out +++ b/tests/qemu-iotests/085.out @@ -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 === diff --git a/tests/qemu-iotests/144.out b/tests/qemu-iotests/144.out index 387855c378..014b2817ee 100644 --- a/tests/qemu-iotests/144.out +++ b/tests/qemu-iotests/144.out @@ -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 diff --git a/tests/qemu-iotests/185.out b/tests/qemu-iotests/185.out index 45bc7cb1a5..57eaf8d699 100644 --- a/tests/qemu-iotests/185.out +++ b/tests/qemu-iotests/185.out @@ -7,12 +7,12 @@ Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864 === Creating backing chain === -Formatting 'TEST_DIR/t.qcow2.mid', fmt=qcow2 size=67108864 backing_file=TEST_DIR/t.qcow2.base backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/t.qcow2.mid', fmt=qcow2 size=67108864 backing_file=TEST_DIR/t.qcow2.base backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 {"return": {}} wrote 4194304/4194304 bytes at offset 0 4 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) {"return": ""} -Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 backing_file=TEST_DIR/t.qcow2.mid backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 backing_file=TEST_DIR/t.qcow2.mid backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16 {"return": {}} === Start commit job and exit qemu === @@ -33,7 +33,7 @@ Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 backing_file=TEST_DIR/t.q === Start mirror job and exit qemu === {"return": {}} -Formatting 'TEST_DIR/t.qcow2.copy', fmt=qcow2 size=67108864 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/t.qcow2.copy', fmt=qcow2 size=67108864 cluster_size=65536 lazy_refcounts=off refcount_bits=16 {"return": {}} {"return": {}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} @@ -42,7 +42,7 @@ Formatting 'TEST_DIR/t.qcow2.copy', fmt=qcow2 size=67108864 encryption=off clust === Start backup job and exit qemu === {"return": {}} -Formatting 'TEST_DIR/t.qcow2.copy', fmt=qcow2 size=67108864 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16 +Formatting 'TEST_DIR/t.qcow2.copy', fmt=qcow2 size=67108864 cluster_size=65536 lazy_refcounts=off refcount_bits=16 {"return": {}} {"return": {}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}} From 1fad1f9400614ebbce9f3ee301fa8d64cbf715e2 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Fri, 23 Jun 2017 17:24:07 +0100 Subject: [PATCH 08/85] qcow: make encrypt_sectors encrypt in place Instead of requiring separate input/output buffers for encrypting data, change encrypt_sectors() to assume use of a single buffer, encrypting in place. One current caller uses the same buffer for input/output already and the other two callers are easily converted to do so. Reviewed-by: Alberto Garcia Reviewed-by: Eric Blake Reviewed-by: Max Reitz Reviewed-by: Kevin Wolf Signed-off-by: Daniel P. Berrange Message-id: 20170623162419.26068-9-berrange@redhat.com Signed-off-by: Max Reitz --- block/qcow.c | 45 +++++++++++++++------------------------------ 1 file changed, 15 insertions(+), 30 deletions(-) diff --git a/block/qcow.c b/block/qcow.c index a442ed73d7..3a3dbf9439 100644 --- a/block/qcow.c +++ b/block/qcow.c @@ -322,11 +322,10 @@ static int qcow_set_key(BlockDriverState *bs, const char *key) } /* The crypt function is compatible with the linux cryptoloop - algorithm for < 4 GB images. NOTE: out_buf == in_buf is - supported */ + algorithm for < 4 GB images. */ 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) + uint8_t *buf, int nb_sectors, bool enc, + Error **errp) { union { uint64_t ll[2]; @@ -345,14 +344,12 @@ static int encrypt_sectors(BDRVQcowState *s, int64_t sector_num, } if (enc) { ret = qcrypto_cipher_encrypt(s->cipher, - in_buf, - out_buf, + buf, buf, 512, errp); } else { ret = qcrypto_cipher_decrypt(s->cipher, - in_buf, - out_buf, + buf, buf, 512, errp); } @@ -360,8 +357,7 @@ static int encrypt_sectors(BDRVQcowState *s, int64_t sector_num, return -1; } sector_num++; - in_buf += 512; - out_buf += 512; + buf += 512; } return 0; } @@ -481,13 +477,12 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, uint64_t start_sect; assert(s->cipher); 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; + memset(s->cluster_data, 0x00, 512); if (encrypt_sectors(s, start_sect + i, - s->cluster_data, - s->cluster_data + 512, 1, + s->cluster_data, 1, true, &err) < 0) { error_free(err); errno = EIO; @@ -665,7 +660,7 @@ static coroutine_fn int qcow_co_readv(BlockDriverState *bs, int64_t sector_num, } if (bs->encrypted) { assert(s->cipher); - if (encrypt_sectors(s, sector_num, buf, buf, + if (encrypt_sectors(s, sector_num, buf, n, false, &err) < 0) { goto fail; } @@ -700,9 +695,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 +703,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; @@ -740,21 +735,14 @@ 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) { + if (encrypt_sectors(s, sector_num, buf, n, true, &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 +761,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; } From d85f4222b4681da7ebf8a90b26e085a68fa2c55a Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Fri, 23 Jun 2017 17:24:08 +0100 Subject: [PATCH 09/85] qcow: convert QCow to use QCryptoBlock for encryption This converts the qcow driver to make use of the QCryptoBlock APIs for encrypting image content. This is only wired up to permit use of the legacy QCow encryption format. Users who wish to have the strong LUKS format should switch to qcow2 instead. With this change it is now required to use the QCryptoSecret object for providing passwords, instead of the current block password APIs / interactive prompting. $QEMU \ -object secret,id=sec0,file=/home/berrange/encrypted.pw \ -drive file=/home/berrange/encrypted.qcow,encrypt.format=aes,\ encrypt.key-secret=sec0 Though note that running QEMU system emulators with the AES encryption is no longer supported, so while the above syntax is valid, QEMU will refuse to actually run the VM in this particular example. Likewise when creating images with the legacy AES-CBC format qemu-img create -f qcow \ --object secret,id=sec0,file=/home/berrange/encrypted.pw \ -o encrypt.format=aes,encrypt.key-secret=sec0 \ /home/berrange/encrypted.qcow 64M Reviewed-by: Max Reitz Reviewed-by: Alberto Garcia Reviewed-by: Eric Blake Signed-off-by: Daniel P. Berrange Message-id: 20170623162419.26068-10-berrange@redhat.com Signed-off-by: Max Reitz --- block/crypto.c | 10 +++ block/crypto.h | 20 +++-- block/qcow.c | 198 +++++++++++++++++++++---------------------- qapi/block-core.json | 38 ++++++++- 4 files changed, 158 insertions(+), 108 deletions(-) diff --git a/block/crypto.c b/block/crypto.c index 9df1e5dde2..da4be74592 100644 --- a/block/crypto.c +++ b/block/crypto.c @@ -181,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; @@ -227,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; diff --git a/block/crypto.h b/block/crypto.h index 3430dcd50c..0f985ea4e2 100644 --- a/block/crypto.h +++ b/block/crypto.h @@ -21,6 +21,19 @@ #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" @@ -30,11 +43,8 @@ #define BLOCK_CRYPTO_OPT_LUKS_ITER_TIME "iter-time" #define BLOCK_CRYPTO_OPT_DEF_LUKS_KEY_SECRET(prefix) \ - { \ - .name = prefix BLOCK_CRYPTO_OPT_LUKS_KEY_SECRET, \ - .type = QEMU_OPT_STRING, \ - .help = "ID of the secret that provides the keyslot passphrase", \ - } + 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) \ { \ diff --git a/block/qcow.c b/block/qcow.c index 3a3dbf9439..db0c5a9016 100644 --- a/block/qcow.c +++ b/block/qcow.c @@ -31,8 +31,10 @@ #include "qemu/bswap.h" #include #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,38 @@ 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, 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; + bs->valid_key = true; } s->cluster_bits = header.cluster_bits; s->cluster_size = 1 << s->cluster_bits; @@ -266,6 +304,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 +314,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,81 +329,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. */ -static int encrypt_sectors(BDRVQcowState *s, int64_t sector_num, - uint8_t *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, - buf, buf, - 512, - errp); - } else { - ret = qcrypto_cipher_decrypt(s->cipher, - buf, buf, - 512, - errp); - } - if (ret < 0) { - return -1; - } - sector_num++; - buf += 512; - } - return 0; -} /* 'allocate' is: * @@ -475,15 +443,16 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, 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; for(i = 0; i < s->cluster_sectors; i++) { if (i < n_start || i >= n_end) { Error *err = NULL; memset(s->cluster_data, 0x00, 512); - if (encrypt_sectors(s, start_sect + i, - s->cluster_data, 1, - true, &err) < 0) { + if (qcrypto_block_encrypt(s->crypto, start_sect + i, + s->cluster_data, + BDRV_SECTOR_SIZE, + &err) < 0) { error_free(err); errno = EIO; return -1; @@ -528,7 +497,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); @@ -659,9 +628,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, - n, false, &err) < 0) { + assert(s->crypto); + if (qcrypto_block_decrypt(s->crypto, sector_num, buf, + n * BDRV_SECTOR_SIZE, &err) < 0) { goto fail; } } @@ -734,8 +703,9 @@ static coroutine_fn int qcow_co_writev(BlockDriverState *bs, int64_t sector_num, } if (bs->encrypted) { Error *err = NULL; - assert(s->cipher); - if (encrypt_sectors(s, sector_num, 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; @@ -770,8 +740,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); @@ -792,6 +762,10 @@ static int qcow_create(const char *filename, QemuOpts *opts, Error **errp) 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), @@ -866,6 +840,10 @@ 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); + + 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'", @@ -874,6 +852,19 @@ static int qcow_create(const char *filename, QemuOpts *opts, Error **errp) 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, NULL, NULL, NULL, errp); + if (!crypto) { + ret = -EINVAL; + goto exit; + } } else { header.crypt_method = cpu_to_be32(QCOW_CRYPT_NONE); } @@ -908,6 +899,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; } @@ -1054,6 +1048,7 @@ static QemuOptsList qcow_create_opts = { .type = QEMU_OPT_STRING, .help = "Encrypt the image, format choices: 'aes'", }, + BLOCK_CRYPTO_OPT_DEF_QCOW_KEY_SECRET("encrypt."), { /* end of list */ } } }; @@ -1074,7 +1069,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, diff --git a/qapi/block-core.json b/qapi/block-core.json index f85c2235c7..c4b7e6e87d 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -2281,6 +2281,42 @@ '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' } } + + ## # @BlockdevOptionsQcow2: # @@ -2976,7 +3012,7 @@ 'null-co': 'BlockdevOptionsNull', 'parallels': 'BlockdevOptionsGenericFormat', 'qcow2': 'BlockdevOptionsQcow2', - 'qcow': 'BlockdevOptionsGenericCOWFormat', + 'qcow': 'BlockdevOptionsQcow', 'qed': 'BlockdevOptionsGenericCOWFormat', 'quorum': 'BlockdevOptionsQuorum', 'raw': 'BlockdevOptionsRaw', From 446d306d23c8b568affec104d74f84f48d5eaa24 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Fri, 23 Jun 2017 17:24:09 +0100 Subject: [PATCH 10/85] qcow2: make qcow2_encrypt_sectors encrypt in place Instead of requiring separate input/output buffers for encrypting data, change qcow2_encrypt_sectors() to assume use of a single buffer, encrypting in place. The current callers all used the same buffer for input/output already. Signed-off-by: Daniel P. Berrange Message-id: 20170623162419.26068-11-berrange@redhat.com Reviewed-by: Alberto Garcia Signed-off-by: Max Reitz --- block/qcow2-cluster.c | 17 ++++++----------- block/qcow2.c | 4 ++-- block/qcow2.h | 3 +-- 3 files changed, 9 insertions(+), 15 deletions(-) diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c index 3d341fd9cb..a570929eb6 100644 --- a/block/qcow2-cluster.c +++ b/block/qcow2-cluster.c @@ -358,11 +358,9 @@ static int count_contiguous_clusters_unallocated(int nb_clusters, } /* The crypt function is compatible with the linux cryptoloop - algorithm for < 4 GB images. NOTE: out_buf == in_buf is - supported */ + algorithm for < 4 GB images. */ int qcow2_encrypt_sectors(BDRVQcow2State *s, int64_t sector_num, - uint8_t *out_buf, const uint8_t *in_buf, - int nb_sectors, bool enc, + uint8_t *buf, int nb_sectors, bool enc, Error **errp) { union { @@ -382,14 +380,12 @@ int qcow2_encrypt_sectors(BDRVQcow2State *s, int64_t sector_num, } if (enc) { ret = qcrypto_cipher_encrypt(s->cipher, - in_buf, - out_buf, + buf, buf, 512, errp); } else { ret = qcrypto_cipher_decrypt(s->cipher, - in_buf, - out_buf, + buf, buf, 512, errp); } @@ -397,8 +393,7 @@ int qcow2_encrypt_sectors(BDRVQcow2State *s, int64_t sector_num, return -1; } sector_num++; - in_buf += 512; - out_buf += 512; + buf += 512; } return 0; } @@ -446,7 +441,7 @@ static bool coroutine_fn do_perform_cow_encrypt(BlockDriverState *bs, 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, + if (qcow2_encrypt_sectors(s, sector, buffer, bytes >> BDRV_SECTOR_BITS, true, NULL) < 0) { return false; } diff --git a/block/qcow2.c b/block/qcow2.c index 8f1822c195..df9caa8773 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -1543,7 +1543,7 @@ static coroutine_fn int qcow2_co_preadv(BlockDriverState *bs, uint64_t offset, assert((cur_bytes & (BDRV_SECTOR_SIZE - 1)) == 0); Error *err = NULL; if (qcow2_encrypt_sectors(s, offset >> BDRV_SECTOR_BITS, - cluster_data, cluster_data, + cluster_data, cur_bytes >> BDRV_SECTOR_BITS, false, &err) < 0) { error_free(err); @@ -1677,7 +1677,7 @@ static coroutine_fn int qcow2_co_pwritev(BlockDriverState *bs, uint64_t offset, qemu_iovec_to_buf(&hd_qiov, 0, cluster_data, hd_qiov.size); if (qcow2_encrypt_sectors(s, offset >> BDRV_SECTOR_BITS, - cluster_data, cluster_data, + cluster_data, cur_bytes >>BDRV_SECTOR_BITS, true, &err) < 0) { error_free(err); diff --git a/block/qcow2.h b/block/qcow2.h index 87b15eb4aa..5a3f07e261 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -545,8 +545,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); From b25b387fa5928e516cb2c9e7fde68e958bd7e50a Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Fri, 23 Jun 2017 17:24:10 +0100 Subject: [PATCH 11/85] qcow2: convert QCow2 to use QCryptoBlock for encryption This converts the qcow2 driver to make use of the QCryptoBlock APIs for encrypting image content, using the legacy QCow2 AES scheme. With this change it is now required to use the QCryptoSecret object for providing passwords, instead of the current block password APIs / interactive prompting. $QEMU \ -object secret,id=sec0,file=/home/berrange/encrypted.pw \ -drive file=/home/berrange/encrypted.qcow2,encrypt.key-secret=sec0 The test 087 could be simplified since there is no longer a difference in behaviour when using blockdev_add with encrypted images for the running vs stopped CPU state. Signed-off-by: Daniel P. Berrange Message-id: 20170623162419.26068-12-berrange@redhat.com Reviewed-by: Alberto Garcia Signed-off-by: Max Reitz --- block/qcow2-cluster.c | 47 +------- block/qcow2.c | 226 +++++++++++++++++++++++++------------ block/qcow2.h | 5 +- qapi/block-core.json | 27 ++++- tests/qemu-iotests/049 | 2 +- tests/qemu-iotests/049.out | 4 +- tests/qemu-iotests/082.out | 27 +++++ tests/qemu-iotests/087 | 32 +++--- tests/qemu-iotests/087.out | 12 +- tests/qemu-iotests/134 | 18 ++- tests/qemu-iotests/134.out | 10 +- tests/qemu-iotests/158 | 19 ++-- tests/qemu-iotests/158.out | 14 +-- tests/qemu-iotests/common | 10 +- 14 files changed, 265 insertions(+), 188 deletions(-) diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c index a570929eb6..71a5e0df07 100644 --- a/block/qcow2-cluster.c +++ b/block/qcow2-cluster.c @@ -357,47 +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. */ -int qcow2_encrypt_sectors(BDRVQcow2State *s, int64_t sector_num, - uint8_t *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, - buf, buf, - 512, - errp); - } else { - ret = qcrypto_cipher_decrypt(s->cipher, - buf, buf, - 512, - errp); - } - if (ret < 0) { - return -1; - } - sector_num++; - buf += 512; - } - return 0; -} - static int coroutine_fn do_perform_cow_read(BlockDriverState *bs, uint64_t src_cluster_offset, unsigned offset_in_cluster, @@ -438,11 +397,11 @@ static bool coroutine_fn do_perform_cow_encrypt(BlockDriverState *bs, BDRVQcow2State *s = bs->opaque; int64_t sector = (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, - bytes >> BDRV_SECTOR_BITS, true, NULL) < 0) { + assert(s->crypto); + if (qcrypto_block_encrypt(s->crypto, sector, buffer, + bytes, NULL) < 0) { return false; } } diff --git a/block/qcow2.c b/block/qcow2.c index df9caa8773..1c66ec120e 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -37,6 +37,9 @@ #include "qemu/option_int.h" #include "qemu/cutils.h" #include "qemu/bswap.h" +#include "qapi/opts-visitor.h" +#include "qapi-visit.h" +#include "block/crypto.h" /* Differences with QCOW: @@ -461,6 +464,7 @@ static QemuOptsList qcow2_runtime_opts = { .type = QEMU_OPT_NUMBER, .help = "Clean unused cache entries after this time (in seconds)", }, + BLOCK_CRYPTO_OPT_DEF_QCOW_KEY_SECRET("encrypt."), { /* end of list */ } }, }; @@ -585,6 +589,7 @@ typedef struct Qcow2ReopenState { int overlap_check; bool discard_passthrough[QCOW2_DISCARD_MAX]; uint64_t cache_clean_interval; + QCryptoBlockOpenOptions *crypto_opts; /* Disk encryption runtime options */ } Qcow2ReopenState; static int qcow2_update_options_prepare(BlockDriverState *bs, @@ -598,9 +603,14 @@ static int qcow2_update_options_prepare(BlockDriverState *bs, int overlap_check_template = 0; uint64_t l2_cache_size, refcount_cache_size; int i; + const char *encryptfmt; + QDict *encryptopts = NULL; Error *local_err = NULL; int ret; + qdict_extract_subqdict(options, &encryptopts, "encrypt."); + encryptfmt = qdict_get_try_str(encryptopts, "format"); + opts = qemu_opts_create(&qcow2_runtime_opts, NULL, 0, &error_abort); qemu_opts_absorb_qdict(opts, options, &local_err); if (local_err) { @@ -751,8 +761,42 @@ static int qcow2_update_options_prepare(BlockDriverState *bs, r->discard_passthrough[QCOW2_DISCARD_OTHER] = qemu_opt_get_bool(opts, QCOW2_OPT_DISCARD_OTHER, false); + switch (s->crypt_method_header) { + case QCOW_CRYPT_NONE: + if (encryptfmt) { + error_setg(errp, "No encryption in image header, but options " + "specified format '%s'", encryptfmt); + ret = -EINVAL; + goto fail; + } + break; + + case 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"); + r->crypto_opts = block_crypto_open_opts_init( + Q_CRYPTO_BLOCK_FORMAT_QCOW, encryptopts, errp); + break; + + default: + error_setg(errp, "Unsupported encryption method %d", + s->crypt_method_header); + break; + } + if (s->crypt_method_header != QCOW_CRYPT_NONE && !r->crypto_opts) { + ret = -EINVAL; + goto fail; + } + ret = 0; fail: + QDECREF(encryptopts); qemu_opts_del(opts); opts = NULL; return ret; @@ -785,6 +829,9 @@ static void qcow2_update_options_commit(BlockDriverState *bs, s->cache_clean_interval = r->cache_clean_interval; cache_clean_timer_init(bs, bdrv_get_aio_context(bs)); } + + qapi_free_QCryptoBlockOpenOptions(s->crypto_opts); + s->crypto_opts = r->crypto_opts; } static void qcow2_update_options_abort(BlockDriverState *bs, @@ -796,6 +843,7 @@ static void qcow2_update_options_abort(BlockDriverState *bs, if (r->refcount_block_cache) { qcow2_cache_destroy(bs, r->refcount_block_cache); } + qapi_free_QCryptoBlockOpenOptions(r->crypto_opts); } static int qcow2_update_options(BlockDriverState *bs, QDict *options, @@ -967,12 +1015,6 @@ static int qcow2_do_open(BlockDriverState *bs, QDict *options, int flags, 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() && @@ -990,6 +1032,7 @@ static int qcow2_do_open(BlockDriverState *bs, QDict *options, int flags, } bs->encrypted = true; + bs->valid_key = true; } s->l2_bits = s->cluster_bits - 3; /* L2 is always one cluster */ @@ -1122,6 +1165,19 @@ static int qcow2_do_open(BlockDriverState *bs, QDict *options, int flags, goto fail; } + if (s->crypt_method_header == QCOW_CRYPT_AES) { + unsigned int cflags = 0; + if (flags & BDRV_O_NO_IO) { + cflags |= QCRYPTO_BLOCK_OPEN_NO_IO; + } + s->crypto = qcrypto_block_open(s->crypto_opts, NULL, NULL, + cflags, errp); + if (!s->crypto) { + ret = -EINVAL; + goto fail; + } + } + /* read the backing file name */ if (header.backing_file_offset != 0) { len = header.backing_file_size; @@ -1202,6 +1258,8 @@ static int qcow2_do_open(BlockDriverState *bs, QDict *options, int flags, } g_free(s->cluster_cache); qemu_vfree(s->cluster_data); + qcrypto_block_free(s->crypto); + qapi_free_QCryptoBlockOpenOptions(s->crypto_opts); return ret; } @@ -1229,41 +1287,6 @@ static void qcow2_refresh_limits(BlockDriverState *bs, Error **errp) bs->bl.pdiscard_alignment = s->cluster_size; } -static int qcow2_set_key(BlockDriverState *bs, const char *key) -{ - BDRVQcow2State *s = bs->opaque; - uint8_t keybuf[16]; - int len, i; - Error *err = NULL; - - 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; -} - static int qcow2_reopen_prepare(BDRVReopenState *state, BlockReopenQueue *queue, Error **errp) { @@ -1379,7 +1402,7 @@ static int64_t coroutine_fn qcow2_co_get_block_status(BlockDriverState *bs, *pnum = bytes >> BDRV_SECTOR_BITS; if (cluster_offset != 0 && ret != QCOW2_CLUSTER_COMPRESSED && - !s->cipher) { + !s->crypto) { index_in_cluster = sector_num & (s->cluster_sectors - 1); cluster_offset |= (index_in_cluster << BDRV_SECTOR_BITS); *file = bs->file->bs; @@ -1436,7 +1459,7 @@ static coroutine_fn int qcow2_co_preadv(BlockDriverState *bs, uint64_t offset, /* prepare next request */ cur_bytes = MIN(bytes, INT_MAX); - if (s->cipher) { + if (s->crypto) { cur_bytes = MIN(cur_bytes, QCOW_MAX_CRYPT_CLUSTERS * s->cluster_size); } @@ -1506,7 +1529,7 @@ static coroutine_fn int qcow2_co_preadv(BlockDriverState *bs, uint64_t offset, } if (bs->encrypted) { - assert(s->cipher); + assert(s->crypto); /* * For encrypted images, read everything into a temporary @@ -1538,14 +1561,15 @@ static coroutine_fn int qcow2_co_preadv(BlockDriverState *bs, uint64_t offset, goto fail; } if (bs->encrypted) { - assert(s->cipher); + assert(s->crypto); assert((offset & (BDRV_SECTOR_SIZE - 1)) == 0); assert((cur_bytes & (BDRV_SECTOR_SIZE - 1)) == 0); Error *err = NULL; - if (qcow2_encrypt_sectors(s, offset >> BDRV_SECTOR_BITS, + if (qcrypto_block_decrypt(s->crypto, + offset >> BDRV_SECTOR_BITS, cluster_data, - cur_bytes >> BDRV_SECTOR_BITS, - false, &err) < 0) { + cur_bytes, + &err) < 0) { error_free(err); ret = -EIO; goto fail; @@ -1661,7 +1685,7 @@ static coroutine_fn int qcow2_co_pwritev(BlockDriverState *bs, uint64_t offset, if (bs->encrypted) { Error *err = NULL; - assert(s->cipher); + assert(s->crypto); if (!cluster_data) { cluster_data = qemu_try_blockalign(bs->file->bs, QCOW_MAX_CRYPT_CLUSTERS @@ -1676,10 +1700,9 @@ static coroutine_fn int qcow2_co_pwritev(BlockDriverState *bs, uint64_t offset, QCOW_MAX_CRYPT_CLUSTERS * s->cluster_size); qemu_iovec_to_buf(&hd_qiov, 0, cluster_data, hd_qiov.size); - if (qcow2_encrypt_sectors(s, offset >> BDRV_SECTOR_BITS, + if (qcrypto_block_encrypt(s->crypto, offset >> BDRV_SECTOR_BITS, cluster_data, - cur_bytes >>BDRV_SECTOR_BITS, - true, &err) < 0) { + cur_bytes, &err) < 0) { error_free(err); ret = -EIO; goto fail; @@ -1804,8 +1827,8 @@ static void qcow2_close(BlockDriverState *bs) qcow2_cache_destroy(bs, s->l2_table_cache); qcow2_cache_destroy(bs, s->refcount_block_cache); - qcrypto_cipher_free(s->cipher); - s->cipher = NULL; + qcrypto_block_free(s->crypto); + s->crypto = NULL; g_free(s->unknown_header_fields); cleanup_unknown_header_ext(bs); @@ -1823,7 +1846,7 @@ static void qcow2_invalidate_cache(BlockDriverState *bs, Error **errp) { BDRVQcow2State *s = bs->opaque; int flags = s->flags; - QCryptoCipher *cipher = NULL; + QCryptoBlock *crypto = NULL; QDict *options; Error *local_err = NULL; int ret; @@ -1833,8 +1856,8 @@ static void qcow2_invalidate_cache(BlockDriverState *bs, Error **errp) * that means we don't have to worry about reopening them here. */ - cipher = s->cipher; - s->cipher = NULL; + crypto = s->crypto; + s->crypto = NULL; qcow2_close(bs); @@ -1855,7 +1878,7 @@ static void qcow2_invalidate_cache(BlockDriverState *bs, Error **errp) return; } - s->cipher = cipher; + s->crypto = crypto; } static size_t header_ext_add(char *buf, uint32_t magic, const void *s, @@ -2079,6 +2102,56 @@ static int qcow2_change_backing_file(BlockDriverState *bs, return qcow2_update_header(bs); } + +static int qcow2_set_up_encryption(BlockDriverState *bs, const char *encryptfmt, + QemuOpts *opts, Error **errp) +{ + BDRVQcow2State *s = bs->opaque; + QCryptoBlockCreateOptions *cryptoopts = NULL; + QCryptoBlock *crypto = NULL; + int ret = -EINVAL; + QDict *options, *encryptopts; + + options = qemu_opts_to_qdict(opts, NULL); + qdict_extract_subqdict(options, &encryptopts, "encrypt."); + QDECREF(options); + + if (!g_str_equal(encryptfmt, "aes")) { + error_setg(errp, "Unknown encryption format '%s', expected 'aes'", + encryptfmt); + ret = -EINVAL; + goto out; + } + cryptoopts = block_crypto_create_opts_init( + Q_CRYPTO_BLOCK_FORMAT_QCOW, encryptopts, errp); + if (!cryptoopts) { + ret = -EINVAL; + goto out; + } + s->crypt_method_header = QCOW_CRYPT_AES; + + crypto = qcrypto_block_create(cryptoopts, + NULL, NULL, + bs, errp); + if (!crypto) { + ret = -EINVAL; + goto out; + } + + ret = qcow2_update_header(bs); + if (ret < 0) { + error_setg_errno(errp, -ret, "Could not write encryption header"); + goto out; + } + + out: + QDECREF(encryptopts); + qcrypto_block_free(crypto); + qapi_free_QCryptoBlockCreateOptions(cryptoopts); + return ret; +} + + static int preallocate(BlockDriverState *bs) { uint64_t bytes; @@ -2273,17 +2346,8 @@ static int qcow2_create2(const char *filename, int64_t total_size, .header_length = cpu_to_be32(sizeof(*header)), }; - if (encryptfmt) { - if (!g_str_equal(encryptfmt, "aes")) { - error_setg(errp, "Unknown encryption format '%s', expected 'aes'", - encryptfmt); - ret = -EINVAL; - goto out; - } - header->crypt_method = cpu_to_be32(QCOW_CRYPT_AES); - } else { - header->crypt_method = cpu_to_be32(QCOW_CRYPT_NONE); - } + /* We'll update this to correct value later */ + header->crypt_method = cpu_to_be32(QCOW_CRYPT_NONE); if (flags & BLOCK_FLAG_LAZY_REFCOUNTS) { header->compatible_features |= @@ -2362,6 +2426,14 @@ static int qcow2_create2(const char *filename, int64_t total_size, } } + /* Want encryption? There you go. */ + if (encryptfmt) { + ret = qcow2_set_up_encryption(blk_bs(blk), encryptfmt, opts, errp); + if (ret < 0) { + goto out; + } + } + /* And if we're supposed to preallocate metadata, do that now */ if (prealloc != PREALLOC_MODE_OFF) { BDRVQcow2State *s = blk_bs(blk)->opaque; @@ -2377,11 +2449,17 @@ static int qcow2_create2(const char *filename, int64_t total_size, blk_unref(blk); blk = NULL; - /* Reopen the image without BDRV_O_NO_FLUSH to flush it before returning */ + /* Reopen the image without BDRV_O_NO_FLUSH to flush it before returning. + * Using BDRV_O_NO_IO, since encryption is now setup we don't want to + * have to setup decryption context. We're not doing any I/O on the top + * level BlockDriverState, only lower layers, where BDRV_O_NO_IO does + * not have effect. + */ options = qdict_new(); qdict_put_str(options, "driver", "qcow2"); blk = blk_new_open(filename, NULL, options, - BDRV_O_RDWR | BDRV_O_NO_BACKING, &local_err); + BDRV_O_RDWR | BDRV_O_NO_BACKING | BDRV_O_NO_IO, + &local_err); if (blk == NULL) { error_propagate(errp, local_err); ret = -EIO; @@ -3226,9 +3304,9 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts, backing_format = qemu_opt_get(opts, BLOCK_OPT_BACKING_FMT); } else if (!strcmp(desc->name, BLOCK_OPT_ENCRYPT)) { encrypt = qemu_opt_get_bool(opts, BLOCK_OPT_ENCRYPT, - !!s->cipher); + !!s->crypto); - if (encrypt != !!s->cipher) { + if (encrypt != !!s->crypto) { error_report("Changing the encryption flag is not supported"); return -ENOTSUP; } @@ -3454,6 +3532,7 @@ static QemuOptsList qcow2_create_opts = { .type = QEMU_OPT_STRING, .help = "Encrypt the image, format choices: 'aes'", }, + BLOCK_CRYPTO_OPT_DEF_QCOW_KEY_SECRET("encrypt."), { .name = BLOCK_OPT_CLUSTER_SIZE, .type = QEMU_OPT_SIZE, @@ -3496,7 +3575,6 @@ BlockDriver bdrv_qcow2 = { .bdrv_create = qcow2_create, .bdrv_has_zero_init = bdrv_has_zero_init_1, .bdrv_co_get_block_status = qcow2_co_get_block_status, - .bdrv_set_key = qcow2_set_key, .bdrv_co_preadv = qcow2_co_preadv, .bdrv_co_pwritev = qcow2_co_pwritev, diff --git a/block/qcow2.h b/block/qcow2.h index 5a3f07e261..4b8961097e 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -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 @@ -257,7 +257,8 @@ typedef struct BDRVQcow2State { CoMutex lock; - QCryptoCipher *cipher; /* current cipher, NULL if no key yet */ + QCryptoBlockOpenOptions *crypto_opts; /* Disk encryption runtime options */ + QCryptoBlock *crypto; /* Disk encryption format driver */ uint32_t crypt_method_header; uint64_t snapshots_offset; int snapshots_size; diff --git a/qapi/block-core.json b/qapi/block-core.json index c4b7e6e87d..1f268eed52 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -2317,6 +2317,26 @@ 'data': { '*encrypt': 'BlockdevQcowEncryption' } } + +## +# @BlockdevQcow2EncryptionFormat: +# @aes: AES-CBC with plain64 initialization venctors +# +# Since: 2.10 +## +{ 'enum': 'BlockdevQcow2EncryptionFormat', + 'data': [ 'aes' ] } + +## +# @BlockdevQcow2Encryption: +# +# Since: 2.10 +## +{ 'union': 'BlockdevQcow2Encryption', + 'base': { 'format': 'BlockdevQcow2EncryptionFormat' }, + 'discriminator': 'format', + 'data': { 'aes': 'QCryptoBlockOptionsQCow' } } + ## # @BlockdevOptionsQcow2: # @@ -2351,6 +2371,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 ## @@ -2364,8 +2387,8 @@ '*cache-size': 'int', '*l2-cache-size': 'int', '*refcount-cache-size': 'int', - '*cache-clean-interval': 'int' } } - + '*cache-clean-interval': 'int', + '*encrypt': 'BlockdevQcow2Encryption' } } ## # @BlockdevOptionsSsh: diff --git a/tests/qemu-iotests/049 b/tests/qemu-iotests/049 index fff07604fc..df35b6d21e 100755 --- a/tests/qemu-iotests/049 +++ b/tests/qemu-iotests/049 @@ -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 diff --git a/tests/qemu-iotests/049.out b/tests/qemu-iotests/049.out index 50e91c8610..003247023e 100644 --- a/tests/qemu-iotests/049.out +++ b/tests/qemu-iotests/049.out @@ -190,8 +190,8 @@ Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=65536 preall 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) == diff --git a/tests/qemu-iotests/082.out b/tests/qemu-iotests/082.out index 621386bf70..3978db564c 100644 --- a/tests/qemu-iotests/082.out +++ b/tests/qemu-iotests/082.out @@ -50,6 +50,7 @@ backing_file File name of a base image backing_fmt Image format of the base image encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) encrypt.format Encrypt the image, format choices: 'aes' +encrypt.key-secret ID of the secret that provides the AES encryption key cluster_size qcow2 cluster size preallocation Preallocation mode (allowed values: off, metadata, falloc, full) lazy_refcounts Postpone refcount updates @@ -64,6 +65,7 @@ backing_file File name of a base image backing_fmt Image format of the base image encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) encrypt.format Encrypt the image, format choices: 'aes' +encrypt.key-secret ID of the secret that provides the AES encryption key cluster_size qcow2 cluster size preallocation Preallocation mode (allowed values: off, metadata, falloc, full) lazy_refcounts Postpone refcount updates @@ -78,6 +80,7 @@ backing_file File name of a base image backing_fmt Image format of the base image encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) encrypt.format Encrypt the image, format choices: 'aes' +encrypt.key-secret ID of the secret that provides the AES encryption key cluster_size qcow2 cluster size preallocation Preallocation mode (allowed values: off, metadata, falloc, full) lazy_refcounts Postpone refcount updates @@ -92,6 +95,7 @@ backing_file File name of a base image backing_fmt Image format of the base image encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) encrypt.format Encrypt the image, format choices: 'aes' +encrypt.key-secret ID of the secret that provides the AES encryption key cluster_size qcow2 cluster size preallocation Preallocation mode (allowed values: off, metadata, falloc, full) lazy_refcounts Postpone refcount updates @@ -106,6 +110,7 @@ backing_file File name of a base image backing_fmt Image format of the base image encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) encrypt.format Encrypt the image, format choices: 'aes' +encrypt.key-secret ID of the secret that provides the AES encryption key cluster_size qcow2 cluster size preallocation Preallocation mode (allowed values: off, metadata, falloc, full) lazy_refcounts Postpone refcount updates @@ -120,6 +125,7 @@ backing_file File name of a base image backing_fmt Image format of the base image encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) encrypt.format Encrypt the image, format choices: 'aes' +encrypt.key-secret ID of the secret that provides the AES encryption key cluster_size qcow2 cluster size preallocation Preallocation mode (allowed values: off, metadata, falloc, full) lazy_refcounts Postpone refcount updates @@ -134,6 +140,7 @@ backing_file File name of a base image backing_fmt Image format of the base image encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) encrypt.format Encrypt the image, format choices: 'aes' +encrypt.key-secret ID of the secret that provides the AES encryption key cluster_size qcow2 cluster size preallocation Preallocation mode (allowed values: off, metadata, falloc, full) lazy_refcounts Postpone refcount updates @@ -148,6 +155,7 @@ backing_file File name of a base image backing_fmt Image format of the base image encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) encrypt.format Encrypt the image, format choices: 'aes' +encrypt.key-secret ID of the secret that provides the AES encryption key cluster_size qcow2 cluster size preallocation Preallocation mode (allowed values: off, metadata, falloc, full) lazy_refcounts Postpone refcount updates @@ -177,6 +185,7 @@ backing_file File name of a base image backing_fmt Image format of the base image encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) encrypt.format Encrypt the image, format choices: 'aes' +encrypt.key-secret ID of the secret that provides the AES encryption key cluster_size qcow2 cluster size preallocation Preallocation mode (allowed values: off, metadata, falloc, full) lazy_refcounts Postpone refcount updates @@ -240,6 +249,7 @@ backing_file File name of a base image backing_fmt Image format of the base image encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) encrypt.format Encrypt the image, format choices: 'aes' +encrypt.key-secret ID of the secret that provides the AES encryption key cluster_size qcow2 cluster size preallocation Preallocation mode (allowed values: off, metadata, falloc, full) lazy_refcounts Postpone refcount updates @@ -254,6 +264,7 @@ backing_file File name of a base image backing_fmt Image format of the base image encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) encrypt.format Encrypt the image, format choices: 'aes' +encrypt.key-secret ID of the secret that provides the AES encryption key cluster_size qcow2 cluster size preallocation Preallocation mode (allowed values: off, metadata, falloc, full) lazy_refcounts Postpone refcount updates @@ -268,6 +279,7 @@ backing_file File name of a base image backing_fmt Image format of the base image encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) encrypt.format Encrypt the image, format choices: 'aes' +encrypt.key-secret ID of the secret that provides the AES encryption key cluster_size qcow2 cluster size preallocation Preallocation mode (allowed values: off, metadata, falloc, full) lazy_refcounts Postpone refcount updates @@ -282,6 +294,7 @@ backing_file File name of a base image backing_fmt Image format of the base image encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) encrypt.format Encrypt the image, format choices: 'aes' +encrypt.key-secret ID of the secret that provides the AES encryption key cluster_size qcow2 cluster size preallocation Preallocation mode (allowed values: off, metadata, falloc, full) lazy_refcounts Postpone refcount updates @@ -296,6 +309,7 @@ backing_file File name of a base image backing_fmt Image format of the base image encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) encrypt.format Encrypt the image, format choices: 'aes' +encrypt.key-secret ID of the secret that provides the AES encryption key cluster_size qcow2 cluster size preallocation Preallocation mode (allowed values: off, metadata, falloc, full) lazy_refcounts Postpone refcount updates @@ -310,6 +324,7 @@ backing_file File name of a base image backing_fmt Image format of the base image encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) encrypt.format Encrypt the image, format choices: 'aes' +encrypt.key-secret ID of the secret that provides the AES encryption key cluster_size qcow2 cluster size preallocation Preallocation mode (allowed values: off, metadata, falloc, full) lazy_refcounts Postpone refcount updates @@ -324,6 +339,7 @@ backing_file File name of a base image backing_fmt Image format of the base image encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) encrypt.format Encrypt the image, format choices: 'aes' +encrypt.key-secret ID of the secret that provides the AES encryption key cluster_size qcow2 cluster size preallocation Preallocation mode (allowed values: off, metadata, falloc, full) lazy_refcounts Postpone refcount updates @@ -338,6 +354,7 @@ backing_file File name of a base image backing_fmt Image format of the base image encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) encrypt.format Encrypt the image, format choices: 'aes' +encrypt.key-secret ID of the secret that provides the AES encryption key cluster_size qcow2 cluster size preallocation Preallocation mode (allowed values: off, metadata, falloc, full) lazy_refcounts Postpone refcount updates @@ -367,6 +384,7 @@ backing_file File name of a base image backing_fmt Image format of the base image encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) encrypt.format Encrypt the image, format choices: 'aes' +encrypt.key-secret ID of the secret that provides the AES encryption key cluster_size qcow2 cluster size preallocation Preallocation mode (allowed values: off, metadata, falloc, full) lazy_refcounts Postpone refcount updates @@ -427,6 +445,7 @@ backing_file File name of a base image backing_fmt Image format of the base image encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) encrypt.format Encrypt the image, format choices: 'aes' +encrypt.key-secret ID of the secret that provides the AES encryption key cluster_size qcow2 cluster size preallocation Preallocation mode (allowed values: off, metadata, falloc, full) lazy_refcounts Postpone refcount updates @@ -441,6 +460,7 @@ backing_file File name of a base image backing_fmt Image format of the base image encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) encrypt.format Encrypt the image, format choices: 'aes' +encrypt.key-secret ID of the secret that provides the AES encryption key cluster_size qcow2 cluster size preallocation Preallocation mode (allowed values: off, metadata, falloc, full) lazy_refcounts Postpone refcount updates @@ -455,6 +475,7 @@ backing_file File name of a base image backing_fmt Image format of the base image encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) encrypt.format Encrypt the image, format choices: 'aes' +encrypt.key-secret ID of the secret that provides the AES encryption key cluster_size qcow2 cluster size preallocation Preallocation mode (allowed values: off, metadata, falloc, full) lazy_refcounts Postpone refcount updates @@ -469,6 +490,7 @@ backing_file File name of a base image backing_fmt Image format of the base image encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) encrypt.format Encrypt the image, format choices: 'aes' +encrypt.key-secret ID of the secret that provides the AES encryption key cluster_size qcow2 cluster size preallocation Preallocation mode (allowed values: off, metadata, falloc, full) lazy_refcounts Postpone refcount updates @@ -483,6 +505,7 @@ backing_file File name of a base image backing_fmt Image format of the base image encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) encrypt.format Encrypt the image, format choices: 'aes' +encrypt.key-secret ID of the secret that provides the AES encryption key cluster_size qcow2 cluster size preallocation Preallocation mode (allowed values: off, metadata, falloc, full) lazy_refcounts Postpone refcount updates @@ -497,6 +520,7 @@ backing_file File name of a base image backing_fmt Image format of the base image encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) encrypt.format Encrypt the image, format choices: 'aes' +encrypt.key-secret ID of the secret that provides the AES encryption key cluster_size qcow2 cluster size preallocation Preallocation mode (allowed values: off, metadata, falloc, full) lazy_refcounts Postpone refcount updates @@ -511,6 +535,7 @@ backing_file File name of a base image backing_fmt Image format of the base image encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) encrypt.format Encrypt the image, format choices: 'aes' +encrypt.key-secret ID of the secret that provides the AES encryption key cluster_size qcow2 cluster size preallocation Preallocation mode (allowed values: off, metadata, falloc, full) lazy_refcounts Postpone refcount updates @@ -525,6 +550,7 @@ backing_file File name of a base image backing_fmt Image format of the base image encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) encrypt.format Encrypt the image, format choices: 'aes' +encrypt.key-secret ID of the secret that provides the AES encryption key cluster_size qcow2 cluster size preallocation Preallocation mode (allowed values: off, metadata, falloc, full) lazy_refcounts Postpone refcount updates @@ -556,6 +582,7 @@ backing_file File name of a base image backing_fmt Image format of the base image encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes) encrypt.format Encrypt the image, format choices: 'aes' +encrypt.key-secret ID of the secret that provides the AES encryption key cluster_size qcow2 cluster size preallocation Preallocation mode (allowed values: off, metadata, falloc, full) lazy_refcounts Postpone refcount updates diff --git a/tests/qemu-iotests/087 b/tests/qemu-iotests/087 index 6d52f7d1b7..1d595b2737 100755 --- a/tests/qemu-iotests/087 +++ b/tests/qemu-iotests/087 @@ -122,24 +122,18 @@ echo echo === Encrypted image === echo -_make_test_img -o encryption=on $size -run_qemu -S < Date: Fri, 23 Jun 2017 17:24:11 +0100 Subject: [PATCH 12/85] qcow2: extend specification to cover LUKS encryption Update the qcow2 specification to describe how the LUKS header is placed inside a qcow2 file, when using LUKS encryption for the qcow2 payload instead of the legacy AES-CBC encryption Reviewed-by: Eric Blake Reviewed-by: Alberto Garcia Reviewed-by: Max Reitz Signed-off-by: Daniel P. Berrange Message-id: 20170623162419.26068-13-berrange@redhat.com Signed-off-by: Max Reitz --- docs/interop/qcow2.txt | 103 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) diff --git a/docs/interop/qcow2.txt b/docs/interop/qcow2.txt index 80cdfd0e91..886a546825 100644 --- a/docs/interop/qcow2.txt +++ b/docs/interop/qcow2.txt @@ -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 @@ -207,6 +209,107 @@ The fields of the bitmaps extension are: 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 == From 4652b8f3e1ec91bb9d6f00e40df7f96d1f1aafee Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Fri, 23 Jun 2017 17:24:12 +0100 Subject: [PATCH 13/85] qcow2: add support for LUKS encryption format This adds support for using LUKS as an encryption format with the qcow2 file, using the new encrypt.format parameter to request "luks" format. e.g. # qemu-img create --object secret,data=123456,id=sec0 \ -f qcow2 -o encrypt.format=luks,encrypt.key-secret=sec0 \ test.qcow2 10G The legacy "encryption=on" parameter still results in creation of the old qcow2 AES format (and is equivalent to the new 'encryption-format=aes'). e.g. the following are equivalent: # qemu-img create --object secret,data=123456,id=sec0 \ -f qcow2 -o encryption=on,encrypt.key-secret=sec0 \ test.qcow2 10G # qemu-img create --object secret,data=123456,id=sec0 \ -f qcow2 -o encryption-format=aes,encrypt.key-secret=sec0 \ test.qcow2 10G With the LUKS format it is necessary to store the LUKS partition header and key material in the QCow2 file. This data can be many MB in size, so cannot go into the QCow2 header region directly. Thus the spec defines a FDE (Full Disk Encryption) header extension that specifies the offset of a set of clusters to hold the FDE headers, as well as the length of that region. The LUKS header is thus stored in these extra allocated clusters before the main image payload. Aside from all the cryptographic differences implied by use of the LUKS format, there is one further key difference between the use of legacy AES and LUKS encryption in qcow2. For LUKS, the initialiazation vectors are generated using the host physical sector as the input, rather than the guest virtual sector. This guarantees unique initialization vectors for all sectors when qcow2 internal snapshots are used, thus giving stronger protection against watermarking attacks. Signed-off-by: Daniel P. Berrange Message-id: 20170623162419.26068-14-berrange@redhat.com Reviewed-by: Alberto Garcia Signed-off-by: Max Reitz --- block/qcow2-cluster.c | 14 +- block/qcow2-refcount.c | 10 ++ block/qcow2.c | 268 +++++++++++++++++++++++++++++++----- block/qcow2.h | 9 ++ qapi/block-core.json | 5 +- tests/qemu-iotests/082.out | 270 +++++++++++++++++++++++++++++-------- 6 files changed, 484 insertions(+), 92 deletions(-) diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c index 71a5e0df07..f06c08f64c 100644 --- a/block/qcow2-cluster.c +++ b/block/qcow2-cluster.c @@ -389,13 +389,16 @@ 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((offset_in_cluster & ~BDRV_SECTOR_MASK) == 0); assert((bytes & ~BDRV_SECTOR_MASK) == 0); @@ -788,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; } diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c index 7c06061aae..81c22e6631 100644 --- a/block/qcow2-refcount.c +++ b/block/qcow2-refcount.c @@ -1856,6 +1856,16 @@ static int calculate_refcounts(BlockDriverState *bs, BdrvCheckResult *res, return ret; } + /* encryption */ + if (s->crypto_header.length) { + ret = inc_refcounts(bs, res, refcount_table, nb_clusters, + s->crypto_header.offset, + s->crypto_header.length); + if (ret < 0) { + return ret; + } + } + return check_refblocks(bs, res, fix, rebuild, refcount_table, nb_clusters); } diff --git a/block/qcow2.c b/block/qcow2.c index 1c66ec120e..7d1c5a30ee 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -66,6 +66,7 @@ typedef struct { #define QCOW2_EXT_MAGIC_END 0 #define QCOW2_EXT_MAGIC_BACKING_FORMAT 0xE2792ACA #define QCOW2_EXT_MAGIC_FEATURE_TABLE 0x6803f857 +#define QCOW2_EXT_MAGIC_CRYPTO_HEADER 0x0537be77 static int qcow2_probe(const uint8_t *buf, int buf_size, const char *filename) { @@ -80,6 +81,86 @@ static int qcow2_probe(const uint8_t *buf, int buf_size, const char *filename) } +static ssize_t qcow2_crypto_hdr_read_func(QCryptoBlock *block, size_t offset, + uint8_t *buf, size_t buflen, + void *opaque, Error **errp) +{ + BlockDriverState *bs = opaque; + BDRVQcow2State *s = bs->opaque; + ssize_t ret; + + if ((offset + buflen) > s->crypto_header.length) { + error_setg(errp, "Request for data outside of extension header"); + return -1; + } + + ret = bdrv_pread(bs->file, + s->crypto_header.offset + offset, buf, buflen); + if (ret < 0) { + error_setg_errno(errp, -ret, "Could not read encryption header"); + return -1; + } + return ret; +} + + +static ssize_t qcow2_crypto_hdr_init_func(QCryptoBlock *block, size_t headerlen, + void *opaque, Error **errp) +{ + BlockDriverState *bs = opaque; + BDRVQcow2State *s = bs->opaque; + int64_t ret; + int64_t clusterlen; + + ret = qcow2_alloc_clusters(bs, headerlen); + if (ret < 0) { + error_setg_errno(errp, -ret, + "Cannot allocate cluster for LUKS header size %zu", + headerlen); + return -1; + } + + s->crypto_header.length = headerlen; + s->crypto_header.offset = ret; + + /* Zero fill remaining space in cluster so it has predictable + * content in case of future spec changes */ + clusterlen = size_to_clusters(s, headerlen) * s->cluster_size; + ret = bdrv_pwrite_zeroes(bs->file, + ret + headerlen, + clusterlen - headerlen, 0); + if (ret < 0) { + error_setg_errno(errp, -ret, "Could not zero fill encryption header"); + return -1; + } + + return ret; +} + + +static ssize_t qcow2_crypto_hdr_write_func(QCryptoBlock *block, size_t offset, + const uint8_t *buf, size_t buflen, + void *opaque, Error **errp) +{ + BlockDriverState *bs = opaque; + BDRVQcow2State *s = bs->opaque; + ssize_t ret; + + if ((offset + buflen) > s->crypto_header.length) { + error_setg(errp, "Request for data outside of extension header"); + return -1; + } + + ret = bdrv_pwrite(bs->file, + s->crypto_header.offset + offset, buf, buflen); + if (ret < 0) { + error_setg_errno(errp, -ret, "Could not read encryption header"); + return -1; + } + return ret; +} + + /* * read qcow2 extension and fill bs * start reading from start_offset @@ -89,7 +170,7 @@ static int qcow2_probe(const uint8_t *buf, int buf_size, const char *filename) */ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset, uint64_t end_offset, void **p_feature_table, - Error **errp) + int flags, Error **errp) { BDRVQcow2State *s = bs->opaque; QCowExtension ext; @@ -165,6 +246,47 @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset, } break; + case QCOW2_EXT_MAGIC_CRYPTO_HEADER: { + unsigned int cflags = 0; + if (s->crypt_method_header != QCOW_CRYPT_LUKS) { + error_setg(errp, "CRYPTO header extension only " + "expected with LUKS encryption method"); + return -EINVAL; + } + if (ext.len != sizeof(Qcow2CryptoHeaderExtension)) { + error_setg(errp, "CRYPTO header extension size %u, " + "but expected size %zu", ext.len, + sizeof(Qcow2CryptoHeaderExtension)); + return -EINVAL; + } + + ret = bdrv_pread(bs->file, offset, &s->crypto_header, ext.len); + if (ret < 0) { + error_setg_errno(errp, -ret, + "Unable to read CRYPTO header extension"); + return ret; + } + be64_to_cpus(&s->crypto_header.offset); + be64_to_cpus(&s->crypto_header.length); + + if ((s->crypto_header.offset % s->cluster_size) != 0) { + error_setg(errp, "Encryption header offset '%" PRIu64 "' is " + "not a multiple of cluster size '%u'", + s->crypto_header.offset, s->cluster_size); + return -EINVAL; + } + + if (flags & BDRV_O_NO_IO) { + cflags |= QCRYPTO_BLOCK_OPEN_NO_IO; + } + s->crypto = qcrypto_block_open(s->crypto_opts, + qcow2_crypto_hdr_read_func, + bs, cflags, errp); + if (!s->crypto) { + return -EINVAL; + } + } break; + default: /* unknown magic - save it in case we need to rewrite the header */ { @@ -464,7 +586,8 @@ static QemuOptsList qcow2_runtime_opts = { .type = QEMU_OPT_NUMBER, .help = "Clean unused cache entries after this time (in seconds)", }, - BLOCK_CRYPTO_OPT_DEF_QCOW_KEY_SECRET("encrypt."), + BLOCK_CRYPTO_OPT_DEF_KEY_SECRET("encrypt.", + "ID of secret providing qcow2 AES key or LUKS passphrase"), { /* end of list */ } }, }; @@ -784,6 +907,19 @@ static int qcow2_update_options_prepare(BlockDriverState *bs, Q_CRYPTO_BLOCK_FORMAT_QCOW, encryptopts, errp); break; + case QCOW_CRYPT_LUKS: + if (encryptfmt && !g_str_equal(encryptfmt, "luks")) { + error_setg(errp, + "Header reported 'luks' encryption format but " + "options specify '%s'", encryptfmt); + ret = -EINVAL; + goto fail; + } + qdict_del(encryptopts, "format"); + r->crypto_opts = block_crypto_open_opts_init( + Q_CRYPTO_BLOCK_FORMAT_LUKS, encryptopts, errp); + break; + default: error_setg(errp, "Unsupported encryption method %d", s->crypt_method_header); @@ -977,7 +1113,7 @@ static int qcow2_do_open(BlockDriverState *bs, QDict *options, int flags, if (s->incompatible_features & ~QCOW2_INCOMPAT_MASK) { void *feature_table = NULL; qcow2_read_extensions(bs, header.header_length, ext_end, - &feature_table, NULL); + &feature_table, flags, NULL); report_unsupported_feature(errp, feature_table, s->incompatible_features & ~QCOW2_INCOMPAT_MASK); @@ -1009,12 +1145,6 @@ static int qcow2_do_open(BlockDriverState *bs, QDict *options, int flags, s->refcount_max = UINT64_C(1) << (s->refcount_bits - 1); s->refcount_max += s->refcount_max - 1; - if (header.crypt_method > QCOW_CRYPT_AES) { - error_setg(errp, "Unsupported encryption method: %" PRIu32, - header.crypt_method); - ret = -EINVAL; - goto fail; - } s->crypt_method_header = header.crypt_method; if (s->crypt_method_header) { if (bdrv_uses_whitelist() && @@ -1031,6 +1161,15 @@ static int qcow2_do_open(BlockDriverState *bs, QDict *options, int flags, goto fail; } + if (s->crypt_method_header == QCOW_CRYPT_AES) { + s->crypt_physical_offset = false; + } else { + /* Assuming LUKS and any future crypt methods we + * add will all use physical offsets, due to the + * fact that the alternative is insecure... */ + s->crypt_physical_offset = true; + } + bs->encrypted = true; bs->valid_key = true; } @@ -1159,20 +1298,31 @@ static int qcow2_do_open(BlockDriverState *bs, QDict *options, int flags, /* read qcow2 extensions */ if (qcow2_read_extensions(bs, header.header_length, ext_end, NULL, - &local_err)) { + flags, &local_err)) { error_propagate(errp, local_err); ret = -EINVAL; goto fail; } - if (s->crypt_method_header == QCOW_CRYPT_AES) { - unsigned int cflags = 0; - if (flags & BDRV_O_NO_IO) { - cflags |= QCRYPTO_BLOCK_OPEN_NO_IO; - } - s->crypto = qcrypto_block_open(s->crypto_opts, NULL, NULL, - cflags, errp); - if (!s->crypto) { + /* qcow2_read_extension may have set up the crypto context + * if the crypt method needs a header region, some methods + * don't need header extensions, so must check here + */ + if (s->crypt_method_header && !s->crypto) { + if (s->crypt_method_header == QCOW_CRYPT_AES) { + unsigned int cflags = 0; + if (flags & BDRV_O_NO_IO) { + cflags |= QCRYPTO_BLOCK_OPEN_NO_IO; + } + s->crypto = qcrypto_block_open(s->crypto_opts, NULL, NULL, + cflags, errp); + if (!s->crypto) { + ret = -EINVAL; + goto fail; + } + } else if (!(flags & BDRV_O_NO_IO)) { + error_setg(errp, "Missing CRYPTO header for crypt method %d", + s->crypt_method_header); ret = -EINVAL; goto fail; } @@ -1566,7 +1716,9 @@ static coroutine_fn int qcow2_co_preadv(BlockDriverState *bs, uint64_t offset, assert((cur_bytes & (BDRV_SECTOR_SIZE - 1)) == 0); Error *err = NULL; if (qcrypto_block_decrypt(s->crypto, - offset >> BDRV_SECTOR_BITS, + (s->crypt_physical_offset ? + cluster_offset + offset_in_cluster : + offset) >> BDRV_SECTOR_BITS, cluster_data, cur_bytes, &err) < 0) { @@ -1700,7 +1852,10 @@ static coroutine_fn int qcow2_co_pwritev(BlockDriverState *bs, uint64_t offset, QCOW_MAX_CRYPT_CLUSTERS * s->cluster_size); qemu_iovec_to_buf(&hd_qiov, 0, cluster_data, hd_qiov.size); - if (qcrypto_block_encrypt(s->crypto, offset >> BDRV_SECTOR_BITS, + if (qcrypto_block_encrypt(s->crypto, + (s->crypt_physical_offset ? + cluster_offset + offset_in_cluster : + offset) >> BDRV_SECTOR_BITS, cluster_data, cur_bytes, &err) < 0) { error_free(err); @@ -2004,6 +2159,22 @@ int qcow2_update_header(BlockDriverState *bs) buflen -= ret; } + /* Full disk encryption header pointer extension */ + if (s->crypto_header.offset != 0) { + cpu_to_be64s(&s->crypto_header.offset); + cpu_to_be64s(&s->crypto_header.length); + ret = header_ext_add(buf, QCOW2_EXT_MAGIC_CRYPTO_HEADER, + &s->crypto_header, sizeof(s->crypto_header), + buflen); + be64_to_cpus(&s->crypto_header.offset); + be64_to_cpus(&s->crypto_header.length); + if (ret < 0) { + goto fail; + } + buf += ret; + buflen -= ret; + } + /* Feature table */ if (s->qcow_version >= 3) { Qcow2Feature features[] = { @@ -2102,6 +2273,16 @@ static int qcow2_change_backing_file(BlockDriverState *bs, return qcow2_update_header(bs); } +static int qcow2_crypt_method_from_format(const char *encryptfmt) +{ + if (g_str_equal(encryptfmt, "luks")) { + return QCOW_CRYPT_LUKS; + } else if (g_str_equal(encryptfmt, "aes")) { + return QCOW_CRYPT_AES; + } else { + return -EINVAL; + } +} static int qcow2_set_up_encryption(BlockDriverState *bs, const char *encryptfmt, QemuOpts *opts, Error **errp) @@ -2111,27 +2292,36 @@ static int qcow2_set_up_encryption(BlockDriverState *bs, const char *encryptfmt, QCryptoBlock *crypto = NULL; int ret = -EINVAL; QDict *options, *encryptopts; + int fmt; options = qemu_opts_to_qdict(opts, NULL); qdict_extract_subqdict(options, &encryptopts, "encrypt."); QDECREF(options); - if (!g_str_equal(encryptfmt, "aes")) { - error_setg(errp, "Unknown encryption format '%s', expected 'aes'", - encryptfmt); - ret = -EINVAL; - goto out; + fmt = qcow2_crypt_method_from_format(encryptfmt); + + switch (fmt) { + case QCOW_CRYPT_LUKS: + cryptoopts = block_crypto_create_opts_init( + Q_CRYPTO_BLOCK_FORMAT_LUKS, encryptopts, errp); + break; + case QCOW_CRYPT_AES: + cryptoopts = block_crypto_create_opts_init( + Q_CRYPTO_BLOCK_FORMAT_QCOW, encryptopts, errp); + break; + default: + error_setg(errp, "Unknown encryption format '%s'", encryptfmt); + break; } - cryptoopts = block_crypto_create_opts_init( - Q_CRYPTO_BLOCK_FORMAT_QCOW, encryptopts, errp); if (!cryptoopts) { ret = -EINVAL; goto out; } - s->crypt_method_header = QCOW_CRYPT_AES; + s->crypt_method_header = fmt; crypto = qcrypto_block_create(cryptoopts, - NULL, NULL, + qcow2_crypto_hdr_init_func, + qcow2_crypto_hdr_write_func, bs, errp); if (!crypto) { ret = -EINVAL; @@ -3268,6 +3458,7 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts, const char *compat = NULL; uint64_t cluster_size = s->cluster_size; bool encrypt; + int encformat; int refcount_bits = s->refcount_bits; Error *local_err = NULL; int ret; @@ -3310,6 +3501,14 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts, error_report("Changing the encryption flag is not supported"); return -ENOTSUP; } + } else if (!strcmp(desc->name, BLOCK_OPT_ENCRYPT_FORMAT)) { + encformat = qcow2_crypt_method_from_format( + qemu_opt_get(opts, BLOCK_OPT_ENCRYPT_FORMAT)); + + if (encformat != s->crypt_method_header) { + error_report("Changing the encryption format is not supported"); + return -ENOTSUP; + } } else if (!strcmp(desc->name, BLOCK_OPT_CLUSTER_SIZE)) { cluster_size = qemu_opt_get_size(opts, BLOCK_OPT_CLUSTER_SIZE, cluster_size); @@ -3530,9 +3729,16 @@ static QemuOptsList qcow2_create_opts = { { .name = BLOCK_OPT_ENCRYPT_FORMAT, .type = QEMU_OPT_STRING, - .help = "Encrypt the image, format choices: 'aes'", + .help = "Encrypt the image, format choices: 'aes', 'luks'", }, - BLOCK_CRYPTO_OPT_DEF_QCOW_KEY_SECRET("encrypt."), + BLOCK_CRYPTO_OPT_DEF_KEY_SECRET("encrypt.", + "ID of secret providing qcow AES key or LUKS passphrase"), + BLOCK_CRYPTO_OPT_DEF_LUKS_CIPHER_ALG("encrypt."), + BLOCK_CRYPTO_OPT_DEF_LUKS_CIPHER_MODE("encrypt."), + BLOCK_CRYPTO_OPT_DEF_LUKS_IVGEN_ALG("encrypt."), + BLOCK_CRYPTO_OPT_DEF_LUKS_IVGEN_HASH_ALG("encrypt."), + BLOCK_CRYPTO_OPT_DEF_LUKS_HASH_ALG("encrypt."), + BLOCK_CRYPTO_OPT_DEF_LUKS_ITER_TIME("encrypt."), { .name = BLOCK_OPT_CLUSTER_SIZE, .type = QEMU_OPT_SIZE, diff --git a/block/qcow2.h b/block/qcow2.h index 4b8961097e..84c9853b1c 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -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 @@ -163,6 +164,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; @@ -257,8 +263,11 @@ typedef struct BDRVQcow2State { CoMutex lock; + 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; diff --git a/qapi/block-core.json b/qapi/block-core.json index 1f268eed52..bb075c098f 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -2325,7 +2325,7 @@ # Since: 2.10 ## { 'enum': 'BlockdevQcow2EncryptionFormat', - 'data': [ 'aes' ] } + 'data': [ 'aes', 'luks' ] } ## # @BlockdevQcow2Encryption: @@ -2335,7 +2335,8 @@ { 'union': 'BlockdevQcow2Encryption', 'base': { 'format': 'BlockdevQcow2EncryptionFormat' }, 'discriminator': 'format', - 'data': { 'aes': 'QCryptoBlockOptionsQCow' } } + 'data': { 'aes': 'QCryptoBlockOptionsQCow', + 'luks': 'QCryptoBlockOptionsLUKS'} } ## # @BlockdevOptionsQcow2: diff --git a/tests/qemu-iotests/082.out b/tests/qemu-iotests/082.out index 3978db564c..dbed67f2ba 100644 --- a/tests/qemu-iotests/082.out +++ b/tests/qemu-iotests/082.out @@ -49,8 +49,14 @@ 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 with format 'aes'. (Deprecated in favor of encrypt.format=aes) -encrypt.format Encrypt the image, format choices: 'aes' -encrypt.key-secret ID of the secret that provides the AES encryption key +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 @@ -64,8 +70,14 @@ 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 with format 'aes'. (Deprecated in favor of encrypt.format=aes) -encrypt.format Encrypt the image, format choices: 'aes' -encrypt.key-secret ID of the secret that provides the AES encryption key +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 @@ -79,8 +91,14 @@ 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 with format 'aes'. (Deprecated in favor of encrypt.format=aes) -encrypt.format Encrypt the image, format choices: 'aes' -encrypt.key-secret ID of the secret that provides the AES encryption key +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 @@ -94,8 +112,14 @@ 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 with format 'aes'. (Deprecated in favor of encrypt.format=aes) -encrypt.format Encrypt the image, format choices: 'aes' -encrypt.key-secret ID of the secret that provides the AES encryption key +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 @@ -109,8 +133,14 @@ 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 with format 'aes'. (Deprecated in favor of encrypt.format=aes) -encrypt.format Encrypt the image, format choices: 'aes' -encrypt.key-secret ID of the secret that provides the AES encryption key +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 @@ -124,8 +154,14 @@ 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 with format 'aes'. (Deprecated in favor of encrypt.format=aes) -encrypt.format Encrypt the image, format choices: 'aes' -encrypt.key-secret ID of the secret that provides the AES encryption key +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,8 +175,14 @@ 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 with format 'aes'. (Deprecated in favor of encrypt.format=aes) -encrypt.format Encrypt the image, format choices: 'aes' -encrypt.key-secret ID of the secret that provides the AES encryption key +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 @@ -154,8 +196,14 @@ 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 with format 'aes'. (Deprecated in favor of encrypt.format=aes) -encrypt.format Encrypt the image, format choices: 'aes' -encrypt.key-secret ID of the secret that provides the AES encryption key +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 @@ -184,8 +232,14 @@ 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 with format 'aes'. (Deprecated in favor of encrypt.format=aes) -encrypt.format Encrypt the image, format choices: 'aes' -encrypt.key-secret ID of the secret that provides the AES encryption key +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 @@ -248,8 +302,14 @@ 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 with format 'aes'. (Deprecated in favor of encrypt.format=aes) -encrypt.format Encrypt the image, format choices: 'aes' -encrypt.key-secret ID of the secret that provides the AES encryption key +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 @@ -263,8 +323,14 @@ 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 with format 'aes'. (Deprecated in favor of encrypt.format=aes) -encrypt.format Encrypt the image, format choices: 'aes' -encrypt.key-secret ID of the secret that provides the AES encryption key +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 @@ -278,8 +344,14 @@ 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 with format 'aes'. (Deprecated in favor of encrypt.format=aes) -encrypt.format Encrypt the image, format choices: 'aes' -encrypt.key-secret ID of the secret that provides the AES encryption key +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 @@ -293,8 +365,14 @@ 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 with format 'aes'. (Deprecated in favor of encrypt.format=aes) -encrypt.format Encrypt the image, format choices: 'aes' -encrypt.key-secret ID of the secret that provides the AES encryption key +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 @@ -308,8 +386,14 @@ 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 with format 'aes'. (Deprecated in favor of encrypt.format=aes) -encrypt.format Encrypt the image, format choices: 'aes' -encrypt.key-secret ID of the secret that provides the AES encryption key +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 @@ -323,8 +407,14 @@ 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 with format 'aes'. (Deprecated in favor of encrypt.format=aes) -encrypt.format Encrypt the image, format choices: 'aes' -encrypt.key-secret ID of the secret that provides the AES encryption key +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 @@ -338,8 +428,14 @@ 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 with format 'aes'. (Deprecated in favor of encrypt.format=aes) -encrypt.format Encrypt the image, format choices: 'aes' -encrypt.key-secret ID of the secret that provides the AES encryption key +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 @@ -353,8 +449,14 @@ 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 with format 'aes'. (Deprecated in favor of encrypt.format=aes) -encrypt.format Encrypt the image, format choices: 'aes' -encrypt.key-secret ID of the secret that provides the AES encryption key +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 @@ -383,8 +485,14 @@ 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 with format 'aes'. (Deprecated in favor of encrypt.format=aes) -encrypt.format Encrypt the image, format choices: 'aes' -encrypt.key-secret ID of the secret that provides the AES encryption key +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 @@ -444,8 +552,14 @@ 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 with format 'aes'. (Deprecated in favor of encrypt.format=aes) -encrypt.format Encrypt the image, format choices: 'aes' -encrypt.key-secret ID of the secret that provides the AES encryption key +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,8 +573,14 @@ 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 with format 'aes'. (Deprecated in favor of encrypt.format=aes) -encrypt.format Encrypt the image, format choices: 'aes' -encrypt.key-secret ID of the secret that provides the AES encryption key +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 @@ -474,8 +594,14 @@ 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 with format 'aes'. (Deprecated in favor of encrypt.format=aes) -encrypt.format Encrypt the image, format choices: 'aes' -encrypt.key-secret ID of the secret that provides the AES encryption key +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 @@ -489,8 +615,14 @@ 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 with format 'aes'. (Deprecated in favor of encrypt.format=aes) -encrypt.format Encrypt the image, format choices: 'aes' -encrypt.key-secret ID of the secret that provides the AES encryption key +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 @@ -504,8 +636,14 @@ 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 with format 'aes'. (Deprecated in favor of encrypt.format=aes) -encrypt.format Encrypt the image, format choices: 'aes' -encrypt.key-secret ID of the secret that provides the AES encryption key +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 @@ -519,8 +657,14 @@ 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 with format 'aes'. (Deprecated in favor of encrypt.format=aes) -encrypt.format Encrypt the image, format choices: 'aes' -encrypt.key-secret ID of the secret that provides the AES encryption key +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 @@ -534,8 +678,14 @@ 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 with format 'aes'. (Deprecated in favor of encrypt.format=aes) -encrypt.format Encrypt the image, format choices: 'aes' -encrypt.key-secret ID of the secret that provides the AES encryption key +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 @@ -549,8 +699,14 @@ 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 with format 'aes'. (Deprecated in favor of encrypt.format=aes) -encrypt.format Encrypt the image, format choices: 'aes' -encrypt.key-secret ID of the secret that provides the AES encryption key +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 @@ -581,8 +737,14 @@ 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 with format 'aes'. (Deprecated in favor of encrypt.format=aes) -encrypt.format Encrypt the image, format choices: 'aes' -encrypt.key-secret ID of the secret that provides the AES encryption key +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 From 426d52d88c54cf048385eeb73d802dd87c1317bd Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Fri, 23 Jun 2017 17:24:13 +0100 Subject: [PATCH 14/85] qcow2: add iotests to cover LUKS encryption support This extends the 087 iotest to cover LUKS encryption when doing blockdev-add. Two further tests are added to validate read/write of LUKS encrypted images with a single file and with a backing file. Reviewed-by: Alberto Garcia Reviewed-by: Max Reitz Signed-off-by: Daniel P. Berrange Message-id: 20170623162419.26068-15-berrange@redhat.com Signed-off-by: Max Reitz --- tests/qemu-iotests/087 | 35 +++++++++++++++- tests/qemu-iotests/087.out | 14 ++++++- tests/qemu-iotests/188 | 76 +++++++++++++++++++++++++++++++++ tests/qemu-iotests/188.out | 18 ++++++++ tests/qemu-iotests/189 | 86 ++++++++++++++++++++++++++++++++++++++ tests/qemu-iotests/189.out | 26 ++++++++++++ tests/qemu-iotests/group | 2 + 7 files changed, 255 insertions(+), 2 deletions(-) create mode 100755 tests/qemu-iotests/188 create mode 100644 tests/qemu-iotests/188.out create mode 100755 tests/qemu-iotests/189 create mode 100644 tests/qemu-iotests/189.out diff --git a/tests/qemu-iotests/087 b/tests/qemu-iotests/087 index 1d595b2737..f8e4903f4f 100755 --- a/tests/qemu-iotests/087 +++ b/tests/qemu-iotests/087 @@ -119,7 +119,7 @@ run_qemu <. +# + +# creator +owner=berrange@redhat.com + +seq=`basename $0` +echo "QA output created by $seq" + +here=`pwd` +status=1 # failure is the default! + +_cleanup() +{ + _cleanup_test_img +} +trap "_cleanup; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter + +_supported_fmt qcow2 +_supported_proto generic +_supported_os Linux + + +size=16M + +SECRET="secret,id=sec0,data=astrochicken" +SECRETALT="secret,id=sec0,data=platypus" + +_make_test_img --object $SECRET -o "encrypt.format=luks,encrypt.key-secret=sec0,encrypt.iter-time=10" $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 ==" +$QEMU_IO --object $SECRET -c "read -P 0 0 $size" --image-opts $IMGSPEC | _filter_qemu_io | _filter_testdir + +echo +echo "== rewriting whole image ==" +$QEMU_IO --object $SECRET -c "write -P 0xa 0 $size" --image-opts $IMGSPEC | _filter_qemu_io | _filter_testdir + +echo +echo "== verify pattern ==" +$QEMU_IO --object $SECRET -c "read -P 0xa 0 $size" --image-opts $IMGSPEC | _filter_qemu_io | _filter_testdir + +echo +echo "== verify open failure with wrong password ==" +$QEMU_IO --object $SECRETALT -c "read -P 0xa 0 $size" --image-opts $IMGSPEC | _filter_qemu_io | _filter_testdir + + +# success, all done +echo "*** done" +rm -f $seq.full +status=0 diff --git a/tests/qemu-iotests/188.out b/tests/qemu-iotests/188.out new file mode 100644 index 0000000000..8af24e5d8b --- /dev/null +++ b/tests/qemu-iotests/188.out @@ -0,0 +1,18 @@ +QA output created by 188 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=16777216 encrypt.format=luks encrypt.key-secret=sec0 encrypt.iter-time=10 + +== reading whole image == +read 16777216/16777216 bytes at offset 0 +16 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +== rewriting whole image == +wrote 16777216/16777216 bytes at offset 0 +16 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +== verify pattern == +read 16777216/16777216 bytes at offset 0 +16 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +== verify open failure with wrong password == +can't open: Invalid password, cannot unlock any keyslot +*** done diff --git a/tests/qemu-iotests/189 b/tests/qemu-iotests/189 new file mode 100755 index 0000000000..54ad980a4e --- /dev/null +++ b/tests/qemu-iotests/189 @@ -0,0 +1,86 @@ +#!/bin/bash +# +# Test encrypted read/write using backing files +# +# 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 . +# + +# creator +owner=berrange@redhat.com + +seq=`basename $0` +echo "QA output created by $seq" + +here=`pwd` +status=1 # failure is the default! + +_cleanup() +{ + _cleanup_test_img +} +trap "_cleanup; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter + +_supported_fmt qcow2 +_supported_proto generic +_supported_os Linux + + +size=16M +TEST_IMG_BASE=$TEST_IMG.base +SECRET0="secret,id=sec0,data=astrochicken" +SECRET1="secret,id=sec1,data=furby" + +TEST_IMG_SAVE=$TEST_IMG +TEST_IMG=$TEST_IMG_BASE +echo "== create base ==" +_make_test_img --object $SECRET0 -o "encrypt.format=luks,encrypt.key-secret=sec0,encrypt.iter-time=10" $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=sec1" +QEMU_IO_OPTIONS=$QEMU_IO_OPTIONS_NO_FMT + +echo +echo "== writing whole image ==" +$QEMU_IO --object $SECRET0 -c "write -P 0xa 0 $size" --image-opts $IMGSPECBASE | _filter_qemu_io | _filter_testdir + +echo +echo "== verify pattern ==" +$QEMU_IO --object $SECRET0 -c "read -P 0xa 0 $size" --image-opts $IMGSPECBASE | _filter_qemu_io | _filter_testdir + +echo "== create overlay ==" +_make_test_img --object $SECRET1 -o "encrypt.format=luks,encrypt.key-secret=sec1,encrypt.iter-time=10" -b "$TEST_IMG_BASE" $size + +echo +echo "== writing part of a cluster ==" +$QEMU_IO --object $SECRET0 --object $SECRET1 -c "write -P 0xe 0 1024" --image-opts $IMGSPEC | _filter_qemu_io | _filter_testdir + +echo +echo "== verify pattern ==" +$QEMU_IO --object $SECRET0 --object $SECRET1 -c "read -P 0xe 0 1024" --image-opts $IMGSPEC | _filter_qemu_io | _filter_testdir +echo +echo "== verify pattern ==" +$QEMU_IO --object $SECRET0 --object $SECRET1 -c "read -P 0xa 1024 64512" --image-opts $IMGSPEC | _filter_qemu_io | _filter_testdir + + +# success, all done +echo "*** done" +rm -f $seq.full +status=0 diff --git a/tests/qemu-iotests/189.out b/tests/qemu-iotests/189.out new file mode 100644 index 0000000000..a0b7c9c24c --- /dev/null +++ b/tests/qemu-iotests/189.out @@ -0,0 +1,26 @@ +QA output created by 189 +== create base == +Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=16777216 encrypt.format=luks encrypt.key-secret=sec0 encrypt.iter-time=10 + +== writing whole image == +wrote 16777216/16777216 bytes at offset 0 +16 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +== verify pattern == +read 16777216/16777216 bytes at offset 0 +16 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +== create overlay == +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=16777216 backing_file=TEST_DIR/t.IMGFMT.base encrypt.format=luks encrypt.key-secret=sec1 encrypt.iter-time=10 + +== writing part of a cluster == +wrote 1024/1024 bytes at offset 0 +1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +== verify pattern == +read 1024/1024 bytes at offset 0 +1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +== verify pattern == +read 64512/64512 bytes at offset 1024 +63 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +*** done diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group index 318ae74b10..613d596356 100644 --- a/tests/qemu-iotests/group +++ b/tests/qemu-iotests/group @@ -176,3 +176,5 @@ 182 rw auto quick 183 rw auto migration 185 rw auto +188 rw auto quick +189 rw auto quick From 23f831c33180656c03c5112552868e1dfa096da4 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Fri, 23 Jun 2017 17:24:14 +0100 Subject: [PATCH 15/85] iotests: enable tests 134 and 158 to work with qcow (v1) The 138 and 158 iotests exercise the legacy qcow2 aes encryption code path and they work fine with qcow v1 too. Reviewed-by: Alberto Garcia Reviewed-by: Max Reitz Signed-off-by: Daniel P. Berrange Message-id: 20170623162419.26068-16-berrange@redhat.com Signed-off-by: Max Reitz --- tests/qemu-iotests/134 | 2 +- tests/qemu-iotests/158 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/qemu-iotests/134 b/tests/qemu-iotests/134 index f851d92e84..99144151b8 100755 --- a/tests/qemu-iotests/134 +++ b/tests/qemu-iotests/134 @@ -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 diff --git a/tests/qemu-iotests/158 b/tests/qemu-iotests/158 index e280b798d1..823c12002e 100755 --- a/tests/qemu-iotests/158 +++ b/tests/qemu-iotests/158 @@ -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 From 788cf9f8c8cbda53843e060540f3e91a060eb744 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Fri, 23 Jun 2017 17:24:15 +0100 Subject: [PATCH 16/85] block: rip out all traces of password prompting Now that qcow & qcow2 are wired up to get encryption keys via the QCryptoSecret object, nothing is relying on the interactive prompting for passwords. All the code related to password prompting can thus be ripped out. Reviewed-by: Alberto Garcia Reviewed-by: Max Reitz Signed-off-by: Daniel P. Berrange Message-id: 20170623162419.26068-17-berrange@redhat.com Signed-off-by: Max Reitz --- hmp.c | 31 ------------------ include/monitor/monitor.h | 7 ---- include/qemu/osdep.h | 2 -- monitor.c | 68 --------------------------------------- qapi-schema.json | 10 +----- qemu-img.c | 31 ------------------ qemu-io.c | 20 ------------ qmp.c | 12 +------ util/oslib-posix.c | 66 ------------------------------------- util/oslib-win32.c | 24 -------------- 10 files changed, 2 insertions(+), 269 deletions(-) diff --git a/hmp.c b/hmp.c index dee40284c1..6d32c40723 100644 --- a/hmp.c +++ b/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); diff --git a/include/monitor/monitor.h b/include/monitor/monitor.h index d2b3aafdb4..83ea4a1aaf 100644 --- a/include/monitor/monitor.h +++ b/include/monitor/monitor.h @@ -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); diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h index 85596341fa..3b74f6fcb2 100644 --- a/include/qemu/osdep.h +++ b/include/qemu/osdep.h @@ -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 diff --git a/monitor.c b/monitor.c index d8ac20f6ca..fa3e3ac251 100644 --- a/monitor.c +++ b/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", diff --git a/qapi-schema.json b/qapi-schema.json index 37c4b95aad..485767f1ab 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -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 diff --git a/qemu-img.c b/qemu-img.c index ae4fe6d83a..7f1de74c13 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -260,29 +260,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 +284,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 +313,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; } diff --git a/qemu-io.c b/qemu-io.c index 8074656b7c..4cfa41c8f9 100644 --- a/qemu-io.c +++ b/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) diff --git a/qmp.c b/qmp.c index 7ee9bcfdcf..84a4f29563 100644 --- a/qmp.c +++ b/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. * diff --git a/util/oslib-posix.c b/util/oslib-posix.c index 5e8b4b39ed..b2dea48f40 100644 --- a/util/oslib-posix.c +++ b/util/oslib-posix.c @@ -414,72 +414,6 @@ void os_mem_prealloc(int fd, char *area, size_t memory, int smp_cpus, } -static struct termios oldtty; - -static void term_exit(void) -{ - tcsetattr(0, TCSANOW, &oldtty); -} - -static void term_init(void) -{ - struct termios tty; - - tcgetattr(0, &tty); - oldtty = tty; - - tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP - |INLCR|IGNCR|ICRNL|IXON); - tty.c_oflag |= OPOST; - tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN); - tty.c_cflag &= ~(CSIZE|PARENB); - tty.c_cflag |= CS8; - tty.c_cc[VMIN] = 1; - tty.c_cc[VTIME] = 0; - - tcsetattr(0, TCSANOW, &tty); - - atexit(term_exit); -} - -int qemu_read_password(char *buf, int buf_size) -{ - uint8_t ch; - int i, ret; - - printf("password: "); - fflush(stdout); - term_init(); - i = 0; - for (;;) { - ret = read(0, &ch, 1); - if (ret == -1) { - if (errno == EAGAIN || errno == EINTR) { - continue; - } else { - break; - } - } else if (ret == 0) { - ret = -1; - break; - } else { - if (ch == '\r' || - ch == '\n') { - ret = 0; - break; - } - if (i < (buf_size - 1)) { - buf[i++] = ch; - } - } - } - term_exit(); - buf[i] = '\0'; - printf("\n"); - return ret; -} - - char *qemu_get_pid_name(pid_t pid) { char *name = NULL; diff --git a/util/oslib-win32.c b/util/oslib-win32.c index 3de9e7777e..69a6286d50 100644 --- a/util/oslib-win32.c +++ b/util/oslib-win32.c @@ -552,30 +552,6 @@ void os_mem_prealloc(int fd, char *area, size_t memory, int smp_cpus, } -/* XXX: put correct support for win32 */ -int qemu_read_password(char *buf, int buf_size) -{ - int c, i; - - printf("Password: "); - fflush(stdout); - i = 0; - for (;;) { - c = getchar(); - if (c < 0) { - buf[i] = '\0'; - return -1; - } else if (c == '\n') { - break; - } else if (i < (buf_size - 1)) { - buf[i++] = c; - } - } - buf[i] = '\0'; - return 0; -} - - char *qemu_get_pid_name(pid_t pid) { /* XXX Implement me */ From c01c214b691d2f9c54a15ea7e486b1750f20fbf8 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Fri, 23 Jun 2017 17:24:16 +0100 Subject: [PATCH 17/85] block: remove all encryption handling APIs Now that all encryption keys must be provided upfront via the QCryptoSecret API and associated block driver properties there is no need for any explicit encryption handling APIs in the block layer. Encryption can be handled transparently within the block driver. We only retain an API for querying whether an image is encrypted or not, since that is a potentially useful piece of metadata to report to the user. Reviewed-by: Alberto Garcia Reviewed-by: Max Reitz Signed-off-by: Daniel P. Berrange Message-id: 20170623162419.26068-18-berrange@redhat.com Signed-off-by: Max Reitz --- block.c | 77 +-------------------------------------- block/crypto.c | 1 - block/qapi.c | 2 +- block/qcow.c | 8 +++- block/qcow2.c | 1 - blockdev.c | 37 +------------------ hmp-commands.hx | 2 + include/block/block.h | 3 -- include/block/block_int.h | 1 - include/qapi/error.h | 1 - qapi/block-core.json | 37 +------------------ qapi/common.json | 5 +-- 12 files changed, 16 insertions(+), 159 deletions(-) diff --git a/block.c b/block.c index 694396281b..edfa6b7a2c 100644 --- a/block.c +++ b/block.c @@ -2573,15 +2573,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); @@ -3072,7 +3064,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); @@ -3502,72 +3493,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; diff --git a/block/crypto.c b/block/crypto.c index da4be74592..3ad4b2067c 100644 --- a/block/crypto.c +++ b/block/crypto.c @@ -308,7 +308,6 @@ static int block_crypto_open_generic(QCryptoBlockFormat format, } bs->encrypted = true; - bs->valid_key = true; ret = 0; cleanup: diff --git a/block/qapi.c b/block/qapi.c index 0a41d59bf3..080eb8f115 100644 --- a/block/qapi.c +++ b/block/qapi.c @@ -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) { diff --git a/block/qcow.c b/block/qcow.c index db0c5a9016..8a24930fbf 100644 --- a/block/qcow.c +++ b/block/qcow.c @@ -220,7 +220,13 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags, goto fail; } bs->encrypted = true; - bs->valid_key = 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; diff --git a/block/qcow2.c b/block/qcow2.c index 7d1c5a30ee..2dd5d51389 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -1171,7 +1171,6 @@ static int qcow2_do_open(BlockDriverState *bs, QDict *options, int flags, } bs->encrypted = true; - bs->valid_key = true; } s->l2_bits = s->cluster_bits - 3; /* L2 is always one cluster */ diff --git a/blockdev.c b/blockdev.c index e2016b6f37..92c59910fc 100644 --- a/blockdev.c +++ b/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)) { @@ -2265,24 +2261,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 +2571,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); @@ -3866,13 +3840,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); } diff --git a/hmp-commands.hx b/hmp-commands.hx index 275ccdfbc7..75f8bac01b 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -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 { diff --git a/include/block/block.h b/include/block/block.h index 4a2725267d..2d637d1da8 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -464,9 +464,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); diff --git a/include/block/block_int.h b/include/block/block_int.h index 701508d35f..b9069c514f 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -529,7 +529,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 */ diff --git a/include/qapi/error.h b/include/qapi/error.h index 7e532d00e9..5d5e737f75 100644 --- a/include/qapi/error.h +++ b/include/qapi/error.h @@ -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, diff --git a/qapi/block-core.json b/qapi/block-core.json index bb075c098f..d04d277128 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -259,8 +259,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) # @@ -946,39 +945,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', diff --git a/qapi/common.json b/qapi/common.json index b626647b2f..8355d5a2f3 100644 --- a/qapi/common.json +++ b/qapi/common.json @@ -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' ] } ## From 1cd9a787a2ee519665d914193e1022791397d621 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Fri, 23 Jun 2017 17:24:17 +0100 Subject: [PATCH 18/85] block: pass option prefix down to crypto layer While the crypto layer uses a fixed option name "key-secret", the upper block layer may have a prefix on the options. e.g. "encrypt.key-secret", in order to avoid clashes between crypto option names & other block option names. To ensure the crypto layer can report accurate error messages, we must tell it what option name prefix was used. Reviewed-by: Alberto Garcia Reviewed-by: Max Reitz Signed-off-by: Daniel P. Berrange Message-id: 20170623162419.26068-19-berrange@redhat.com Signed-off-by: Max Reitz --- block/crypto.c | 4 ++-- block/qcow.c | 7 ++++--- block/qcow2.c | 8 ++++---- crypto/block-luks.c | 8 ++++++-- crypto/block-qcow.c | 8 ++++++-- crypto/block.c | 6 ++++-- crypto/blockpriv.h | 2 ++ include/crypto/block.h | 6 +++++- tests/test-crypto-block.c | 8 ++++---- 9 files changed, 37 insertions(+), 20 deletions(-) diff --git a/block/crypto.c b/block/crypto.c index 3ad4b2067c..c561cbad7a 100644 --- a/block/crypto.c +++ b/block/crypto.c @@ -296,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, @@ -340,7 +340,7 @@ static int block_crypto_create_generic(QCryptoBlockFormat format, return -1; } - crypto = qcrypto_block_create(create_opts, + crypto = qcrypto_block_create(create_opts, NULL, block_crypto_init_func, block_crypto_write_func, &data, diff --git a/block/qcow.c b/block/qcow.c index 8a24930fbf..2002c169be 100644 --- a/block/qcow.c +++ b/block/qcow.c @@ -208,8 +208,8 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags, if (flags & BDRV_O_NO_IO) { cflags |= QCRYPTO_BLOCK_OPEN_NO_IO; } - s->crypto = qcrypto_block_open(crypto_opts, NULL, NULL, - cflags, errp); + s->crypto = qcrypto_block_open(crypto_opts, "encrypt.", + NULL, NULL, cflags, errp); if (!s->crypto) { ret = -EINVAL; goto fail; @@ -866,7 +866,8 @@ static int qcow_create(const char *filename, QemuOpts *opts, Error **errp) goto exit; } - crypto = qcrypto_block_create(crypto_opts, NULL, NULL, NULL, errp); + crypto = qcrypto_block_create(crypto_opts, "encrypt.", + NULL, NULL, NULL, errp); if (!crypto) { ret = -EINVAL; goto exit; diff --git a/block/qcow2.c b/block/qcow2.c index 2dd5d51389..f597fd0014 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -279,7 +279,7 @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset, if (flags & BDRV_O_NO_IO) { cflags |= QCRYPTO_BLOCK_OPEN_NO_IO; } - s->crypto = qcrypto_block_open(s->crypto_opts, + s->crypto = qcrypto_block_open(s->crypto_opts, "encrypt.", qcow2_crypto_hdr_read_func, bs, cflags, errp); if (!s->crypto) { @@ -1313,8 +1313,8 @@ static int qcow2_do_open(BlockDriverState *bs, QDict *options, int flags, if (flags & BDRV_O_NO_IO) { cflags |= QCRYPTO_BLOCK_OPEN_NO_IO; } - s->crypto = qcrypto_block_open(s->crypto_opts, NULL, NULL, - cflags, errp); + s->crypto = qcrypto_block_open(s->crypto_opts, "encrypt.", + NULL, NULL, cflags, errp); if (!s->crypto) { ret = -EINVAL; goto fail; @@ -2318,7 +2318,7 @@ static int qcow2_set_up_encryption(BlockDriverState *bs, const char *encryptfmt, } s->crypt_method_header = fmt; - crypto = qcrypto_block_create(cryptoopts, + crypto = qcrypto_block_create(cryptoopts, "encrypt.", qcow2_crypto_hdr_init_func, qcow2_crypto_hdr_write_func, bs, errp); diff --git a/crypto/block-luks.c b/crypto/block-luks.c index 2b97d89a69..afb8543108 100644 --- a/crypto/block-luks.c +++ b/crypto/block-luks.c @@ -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); diff --git a/crypto/block-qcow.c b/crypto/block-qcow.c index be88c6f0ef..a456fe338b 100644 --- a/crypto/block-qcow.c +++ b/crypto/block-qcow.c @@ -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 */ diff --git a/crypto/block.c b/crypto/block.c index 64c8420425..b097d451af 100644 --- a/crypto/block.c +++ b/crypto/block.c @@ -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; diff --git a/crypto/blockpriv.h b/crypto/blockpriv.h index 68f0f06704..0edb810e22 100644 --- a/crypto/blockpriv.h +++ b/crypto/blockpriv.h @@ -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, diff --git a/include/crypto/block.h b/include/crypto/block.h index 013a435f1b..f0e543bee1 100644 --- a/include/crypto/block.h +++ b/include/crypto/block.h @@ -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, diff --git a/tests/test-crypto-block.c b/tests/test-crypto-block.c index 95c4bd5da3..bd7fe593e3 100644 --- a/tests/test-crypto-block.c +++ b/tests/test-crypto-block.c @@ -281,7 +281,7 @@ static void test_block(gconstpointer opaque) memset(&header, 0, sizeof(header)); buffer_init(&header, "header"); - blk = qcrypto_block_create(data->create_opts, + blk = qcrypto_block_create(data->create_opts, NULL, test_block_init_func, test_block_write_func, &header, @@ -300,7 +300,7 @@ static void test_block(gconstpointer opaque) object_unparent(sec); /* Ensure we can't open without the secret */ - blk = qcrypto_block_open(data->open_opts, + blk = qcrypto_block_open(data->open_opts, NULL, test_block_read_func, &header, 0, @@ -308,7 +308,7 @@ static void test_block(gconstpointer opaque) g_assert(blk == NULL); /* Ensure we can't open without the secret, unless NO_IO */ - blk = qcrypto_block_open(data->open_opts, + blk = qcrypto_block_open(data->open_opts, NULL, test_block_read_func, &header, QCRYPTO_BLOCK_OPEN_NO_IO, @@ -322,7 +322,7 @@ static void test_block(gconstpointer opaque) /* Now open for real with secret */ sec = test_block_secret(); - blk = qcrypto_block_open(data->open_opts, + blk = qcrypto_block_open(data->open_opts, NULL, test_block_read_func, &header, 0, From 0a12f6f80eeebeebd492db7d8c4237fe5c712f68 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Fri, 23 Jun 2017 17:24:18 +0100 Subject: [PATCH 19/85] qcow2: report encryption specific image information Currently 'qemu-img info' reports a simple "encrypted: yes" field. This is not very useful now that qcow2 can support multiple encryption formats. Users want to know which format is in use and some data related to it. Wire up usage of the qcrypto_block_get_info() method so that 'qemu-img info' can report about the encryption format and parameters in use $ qemu-img create \ --object secret,id=sec0,data=123456 \ -o encrypt.format=luks,encrypt.key-secret=sec0 \ -f qcow2 demo.qcow2 1G Formatting 'demo.qcow2', fmt=qcow2 size=1073741824 \ encryption=off encrypt.format=luks encrypt.key-secret=sec0 \ cluster_size=65536 lazy_refcounts=off refcount_bits=16 $ qemu-img info demo.qcow2 image: demo.qcow2 file format: qcow2 virtual size: 1.0G (1073741824 bytes) disk size: 480K encrypted: yes cluster_size: 65536 Format specific information: compat: 1.1 lazy refcounts: false refcount bits: 16 encrypt: ivgen alg: plain64 hash alg: sha256 cipher alg: aes-256 uuid: 3fa930c4-58c8-4ef7-b3c5-314bb5af21f3 format: luks cipher mode: xts slots: [0]: active: true iters: 1839058 key offset: 4096 stripes: 4000 [1]: active: false key offset: 262144 [2]: active: false key offset: 520192 [3]: active: false key offset: 778240 [4]: active: false key offset: 1036288 [5]: active: false key offset: 1294336 [6]: active: false key offset: 1552384 [7]: active: false key offset: 1810432 payload offset: 2068480 master key iters: 438487 corrupt: false With the legacy "AES" encryption we just report the format name $ qemu-img create \ --object secret,id=sec0,data=123456 \ -o encrypt.format=aes,encrypt.key-secret=sec0 \ -f qcow2 demo.qcow2 1G Formatting 'demo.qcow2', fmt=qcow2 size=1073741824 \ encryption=off encrypt.format=aes encrypt.key-secret=sec0 \ cluster_size=65536 lazy_refcounts=off refcount_bits=16 $ ./qemu-img info demo.qcow2 image: demo.qcow2 file format: qcow2 virtual size: 1.0G (1073741824 bytes) disk size: 196K encrypted: yes cluster_size: 65536 Format specific information: compat: 1.1 lazy refcounts: false refcount bits: 16 encrypt: format: aes corrupt: false Reviewed-by: Alberto Garcia Reviewed-by: Max Reitz Reviewed-by: Eric Blake Signed-off-by: Daniel P. Berrange Message-id: 20170623162419.26068-20-berrange@redhat.com Signed-off-by: Max Reitz --- block/qcow2.c | 32 +++++++++++++++++++++++++++++++- qapi/block-core.json | 27 ++++++++++++++++++++++++++- 2 files changed, 57 insertions(+), 2 deletions(-) diff --git a/block/qcow2.c b/block/qcow2.c index f597fd0014..5339aa0cb1 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -3241,8 +3241,14 @@ static int qcow2_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) static ImageInfoSpecific *qcow2_get_specific_info(BlockDriverState *bs) { BDRVQcow2State *s = bs->opaque; - ImageInfoSpecific *spec_info = g_new(ImageInfoSpecific, 1); + ImageInfoSpecific *spec_info; + QCryptoBlockInfo *encrypt_info = NULL; + if (s->crypto != NULL) { + encrypt_info = qcrypto_block_get_info(s->crypto, &error_abort); + } + + spec_info = g_new(ImageInfoSpecific, 1); *spec_info = (ImageInfoSpecific){ .type = IMAGE_INFO_SPECIFIC_KIND_QCOW2, .u.qcow2.data = g_new(ImageInfoSpecificQCow2, 1), @@ -3269,6 +3275,30 @@ static ImageInfoSpecific *qcow2_get_specific_info(BlockDriverState *bs) assert(false); } + if (encrypt_info) { + ImageInfoSpecificQCow2Encryption *qencrypt = + g_new(ImageInfoSpecificQCow2Encryption, 1); + switch (encrypt_info->format) { + case Q_CRYPTO_BLOCK_FORMAT_QCOW: + qencrypt->format = BLOCKDEV_QCOW2_ENCRYPTION_FORMAT_AES; + qencrypt->u.aes = encrypt_info->u.qcow; + break; + case Q_CRYPTO_BLOCK_FORMAT_LUKS: + qencrypt->format = BLOCKDEV_QCOW2_ENCRYPTION_FORMAT_LUKS; + qencrypt->u.luks = encrypt_info->u.luks; + break; + default: + abort(); + } + /* Since we did shallow copy above, erase any pointers + * in the original info */ + memset(&encrypt_info->u, 0, sizeof(encrypt_info->u)); + qapi_free_QCryptoBlockInfo(encrypt_info); + + spec_info->u.qcow2.data->has_encrypt = true; + spec_info->u.qcow2.data->encrypt = qencrypt; + } + return spec_info; } diff --git a/qapi/block-core.json b/qapi/block-core.json index d04d277128..957096395a 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -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' } } ## From 12f7efd02ee4e7144b842a1437defb997b9ae66b Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Fri, 23 Jun 2017 17:24:19 +0100 Subject: [PATCH 20/85] docs: document encryption options for qcow, qcow2 and luks Expand the image format docs to cover the new options for the qcow, qcow2 and luks disk image formats Reviewed-by: Alberto Garcia Reviewed-by: Eric Blake Signed-off-by: Daniel P. Berrange Message-id: 20170623162419.26068-21-berrange@redhat.com Signed-off-by: Max Reitz --- qemu-doc.texi | 123 ++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 115 insertions(+), 8 deletions(-) diff --git a/qemu-doc.texi b/qemu-doc.texi index d2986cba50..48af5155c7 100644 --- a/qemu-doc.texi +++ b/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 From a9ed6a919360b998009508be03b056f2b7417ac5 Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Wed, 21 Jun 2017 15:11:57 +0200 Subject: [PATCH 21/85] iotests: 181 does not work for all formats Test 181 only works for formats which support live migration (naturally, as it is a live migration test). Disable it for all formats which do not. Signed-off-by: Max Reitz Message-id: 20170621131157.16584-1-mreitz@redhat.com Reviewed-by: John Snow Signed-off-by: Max Reitz --- tests/qemu-iotests/181 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/qemu-iotests/181 b/tests/qemu-iotests/181 index e969a2a94f..f73ad5af2a 100755 --- a/tests/qemu-iotests/181 +++ b/tests/qemu-iotests/181 @@ -43,6 +43,8 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 . ./common.qemu _supported_fmt generic +# Formats that do not support live migration +_unsupported_fmt qcow vdi vhdx vmdk vpc vvfat _supported_proto generic _supported_os Linux From 5ce6bfe255091d532ec4555d0ede816294cb1703 Mon Sep 17 00:00:00 2001 From: "sochin.jiang" Date: Mon, 26 Jun 2017 19:04:24 +0800 Subject: [PATCH 22/85] mirror: Fix inconsistent backing AioContext for after mirroring mirror_complete opens the backing chain, which should have the same AioContext as the top when using iothreads. Make the code guarantee this, which fixes a failed assertion in bdrv_attach_child. Signed-off-by: sochin.jiang Message-id: 1498475064-39816-1-git-send-email-sochin.jiang@huawei.com [mreitz: Reworded commit message] Signed-off-by: Max Reitz --- block.c | 1 + 1 file changed, 1 insertion(+) diff --git a/block.c b/block.c index edfa6b7a2c..b9e5114a27 100644 --- a/block.c +++ b/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 */ From b5d1f154889a2e3e6a5da845a10719cea0d4e631 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 28 Jun 2017 15:05:01 +0300 Subject: [PATCH 23/85] specs/qcow2: fix bitmap granularity qemu-specific note Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: John Snow Message-id: 20170628120530.31251-2-vsementsov@virtuozzo.com Signed-off-by: Max Reitz --- docs/interop/qcow2.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/interop/qcow2.txt b/docs/interop/qcow2.txt index 886a546825..aee3553a4f 100644 --- a/docs/interop/qcow2.txt +++ b/docs/interop/qcow2.txt @@ -575,8 +575,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 From b348c262cc6d820a43b1453bc7d745c21619f8aa Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 28 Jun 2017 15:05:02 +0300 Subject: [PATCH 24/85] specs/qcow2: do not use wording 'bitmap header' A bitmap directory entry is sometimes called a 'bitmap header'. This patch leaves only one name - 'bitmap directory entry'. The name 'bitmap header' creates misunderstandings with 'qcow2 header' and 'qcow2 bitmap header extension' (which is extension of qcow2 header) Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Eric Blake Reviewed-by: John Snow Message-id: 20170628120530.31251-3-vsementsov@virtuozzo.com Signed-off-by: Max Reitz --- docs/interop/qcow2.txt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/interop/qcow2.txt b/docs/interop/qcow2.txt index aee3553a4f..d7fdb1fee3 100644 --- a/docs/interop/qcow2.txt +++ b/docs/interop/qcow2.txt @@ -203,7 +203,7 @@ 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 @@ -529,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: From f63ea4e92bad1dbad58b198f51ac48657c1facbd Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 28 Jun 2017 15:05:03 +0300 Subject: [PATCH 25/85] hbitmap: improve dirty iter Make dirty iter resistant to resetting bits in corresponding HBitmap. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Max Reitz Reviewed-by: John Snow Message-id: 20170628120530.31251-4-vsementsov@virtuozzo.com Signed-off-by: Max Reitz --- include/qemu/hbitmap.h | 26 ++++---------------------- util/hbitmap.c | 23 ++++++++++++++++++++++- 2 files changed, 26 insertions(+), 23 deletions(-) diff --git a/include/qemu/hbitmap.h b/include/qemu/hbitmap.h index 9239fe515e..6b04391266 100644 --- a/include/qemu/hbitmap.h +++ b/include/qemu/hbitmap.h @@ -256,10 +256,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 +297,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: diff --git a/util/hbitmap.c b/util/hbitmap.c index 35088e19c4..0b38817505 100644 --- a/util/hbitmap.c +++ b/util/hbitmap.c @@ -106,8 +106,9 @@ unsigned long hbitmap_iter_skip_words(HBitmapIter *hbi) unsigned long cur; do { - cur = hbi->cur[--i]; + i--; pos >>= BITS_PER_LEVEL; + cur = hbi->cur[i] & hb->levels[i][pos]; } while (cur == 0); /* Check for end of iteration. We always use fewer than BITS_PER_LONG @@ -139,6 +140,26 @@ unsigned long hbitmap_iter_skip_words(HBitmapIter *hbi) return cur; } +int64_t hbitmap_iter_next(HBitmapIter *hbi) +{ + unsigned long cur = hbi->cur[HBITMAP_LEVELS - 1] & + hbi->hb->levels[HBITMAP_LEVELS - 1][hbi->pos]; + 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; +} + void hbitmap_iter_init(HBitmapIter *hbi, const HBitmap *hb, uint64_t first) { unsigned i, bit; From eedc4b6d8d88f233a6b2dded21779dcbb836cb08 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 28 Jun 2017 15:05:04 +0300 Subject: [PATCH 26/85] tests: add hbitmap iter test Test that hbitmap iter is resistant to bitmap resetting. Signed-off-by: Vladimir Sementsov-Ogievskiy Signed-off-by: Denis V. Lunev Reviewed-by: Max Reitz Reviewed-by: John Snow Message-id: 20170628120530.31251-5-vsementsov@virtuozzo.com Signed-off-by: Max Reitz --- tests/test-hbitmap.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tests/test-hbitmap.c b/tests/test-hbitmap.c index 23773d2051..1acb353889 100644 --- a/tests/test-hbitmap.c +++ b/tests/test-hbitmap.c @@ -909,6 +909,22 @@ static void hbitmap_test_add(const char *testpath, hbitmap_test_teardown); } +static void test_hbitmap_iter_and_reset(TestHBitmapData *data, + const void *unused) +{ + HBitmapIter hbi; + + hbitmap_test_init(data, L1 * 2, 0); + hbitmap_set(data->hb, 0, data->size); + + hbitmap_iter_init(&hbi, data->hb, BITS_PER_LONG - 1); + + hbitmap_iter_next(&hbi); + + hbitmap_reset_all(data->hb); + hbitmap_iter_next(&hbi); +} + int main(int argc, char **argv) { g_test_init(&argc, &argv, NULL); @@ -966,6 +982,9 @@ int main(int argc, char **argv) test_hbitmap_serialize_part); hbitmap_test_add("/hbitmap/serialize/zeroes", test_hbitmap_serialize_zeroes); + + hbitmap_test_add("/hbitmap/iter/iter_and_reset", + test_hbitmap_iter_and_reset); g_test_run(); return 0; From ba06ff1a5c4d080cc8e88ec2d7c3472c20d33f1b Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 28 Jun 2017 15:05:05 +0300 Subject: [PATCH 27/85] block: fix bdrv_dirty_bitmap_granularity signature Make getter signature const-correct. This allows other functions with const dirty bitmap parameter use bdrv_dirty_bitmap_granularity(). Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Eric Blake Reviewed-by: John Snow Reviewed-by: Kevin Wolf Message-id: 20170628120530.31251-6-vsementsov@virtuozzo.com Signed-off-by: Max Reitz --- block/dirty-bitmap.c | 2 +- include/block/dirty-bitmap.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c index a04c6e4154..df0110cf9f 100644 --- a/block/dirty-bitmap.c +++ b/block/dirty-bitmap.c @@ -455,7 +455,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); } diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h index ad6558af56..ab89f08e3d 100644 --- a/include/block/dirty-bitmap.h +++ b/include/block/dirty-bitmap.h @@ -29,7 +29,7 @@ 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); From 6bdc8b719a1617ec5ddfb13e78054df22fa12f84 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 28 Jun 2017 15:05:06 +0300 Subject: [PATCH 28/85] block/dirty-bitmap: add deserialize_ones func Add bdrv_dirty_bitmap_deserialize_ones() function, which is needed for qcow2 bitmap loading, to handle unallocated bitmap parts, marked as all-ones. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Kevin Wolf Reviewed-by: John Snow Message-id: 20170628120530.31251-7-vsementsov@virtuozzo.com Signed-off-by: Max Reitz --- block/dirty-bitmap.c | 7 +++++++ include/block/dirty-bitmap.h | 3 +++ include/qemu/hbitmap.h | 15 +++++++++++++++ util/hbitmap.c | 17 +++++++++++++++++ 4 files changed, 42 insertions(+) diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c index df0110cf9f..f502c45a70 100644 --- a/block/dirty-bitmap.c +++ b/block/dirty-bitmap.c @@ -586,6 +586,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); diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h index ab89f08e3d..05451c727d 100644 --- a/include/block/dirty-bitmap.h +++ b/include/block/dirty-bitmap.h @@ -66,6 +66,9 @@ 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); /* Functions that require manual locking. */ diff --git a/include/qemu/hbitmap.h b/include/qemu/hbitmap.h index 6b04391266..b52304ac29 100644 --- a/include/qemu/hbitmap.h +++ b/include/qemu/hbitmap.h @@ -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. diff --git a/util/hbitmap.c b/util/hbitmap.c index 0b38817505..0c1591a594 100644 --- a/util/hbitmap.c +++ b/util/hbitmap.c @@ -551,6 +551,23 @@ void hbitmap_deserialize_zeroes(HBitmap *hb, uint64_t start, uint64_t count, } } +void hbitmap_deserialize_ones(HBitmap *hb, uint64_t start, uint64_t count, + bool finish) +{ + uint64_t el_count; + unsigned long *first; + + if (!count) { + return; + } + serialization_chunk(hb, start, count, &first, &el_count); + + memset(first, 0xff, el_count * sizeof(unsigned long)); + if (finish) { + hbitmap_deserialize_finish(hb); + } +} + void hbitmap_deserialize_finish(HBitmap *bitmap) { int64_t i, size, prev_size; From 8a5bb1f114c5959cf6b247a737394afb0c518b40 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 28 Jun 2017 15:05:07 +0300 Subject: [PATCH 29/85] qcow2-refcount: rename inc_refcounts() and make it public This is needed for the following patch, which will introduce refcounts checking for qcow2 bitmaps. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Max Reitz Reviewed-by: John Snow Message-id: 20170628120530.31251-8-vsementsov@virtuozzo.com [mreitz: s/inc_refcounts/qcow2_inc_refcounts_imrt/ in one more (new) place] Signed-off-by: Max Reitz --- block/qcow2-refcount.c | 59 ++++++++++++++++++++++-------------------- block/qcow2.h | 4 +++ 2 files changed, 35 insertions(+), 28 deletions(-) diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c index 81c22e6631..8add3d5640 100644 --- a/block/qcow2-refcount.c +++ b/block/qcow2-refcount.c @@ -1323,11 +1323,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 +1419,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 +1454,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 +1509,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 +1539,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; } @@ -1757,14 +1759,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 +1782,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 +1823,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,25 +1845,25 @@ 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 = inc_refcounts(bs, res, refcount_table, nb_clusters, - s->crypto_header.offset, - 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; } diff --git a/block/qcow2.h b/block/qcow2.h index 84c9853b1c..a272a39ab2 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -544,6 +544,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, From 88ddffae8fc1e30cc907c2dbb989b7eba9e62319 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 28 Jun 2017 15:05:08 +0300 Subject: [PATCH 30/85] qcow2: add bitmaps extension Add bitmap extension as specified in docs/specs/qcow2.txt. For now, just mirror extension header into Qcow2 state and check constraints. Also, calculate refcounts for qcow2 bitmaps, to not break qemu-img check. For now, disable image resize if it has bitmaps. It will be fixed later. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Max Reitz Reviewed-by: John Snow Message-id: 20170628120530.31251-9-vsementsov@virtuozzo.com Signed-off-by: Max Reitz --- block/Makefile.objs | 2 +- block/qcow2-bitmap.c | 439 +++++++++++++++++++++++++++++++++++++++++ block/qcow2-refcount.c | 6 + block/qcow2.c | 125 +++++++++++- block/qcow2.h | 27 +++ 5 files changed, 593 insertions(+), 6 deletions(-) create mode 100644 block/qcow2-bitmap.c diff --git a/block/Makefile.objs b/block/Makefile.objs index f9368b52b8..2aaede4ae1 100644 --- a/block/Makefile.objs +++ b/block/Makefile.objs @@ -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 diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c new file mode 100644 index 0000000000..b8e472b3e8 --- /dev/null +++ b/block/qcow2-bitmap.c @@ -0,0 +1,439 @@ +/* + * Bitmaps for the QCOW version 2 format + * + * Copyright (c) 2014-2017 Vladimir Sementsov-Ogievskiy + * + * This file is derived from qcow2-snapshot.c, original copyright: + * Copyright (c) 2004-2006 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" + +#include "block/block_int.h" +#include "block/qcow2.h" + +/* NOTICE: BME here means Bitmaps Extension and used as a namespace for + * _internal_ constants. Please do not use this _internal_ abbreviation for + * other needs and/or outside of this file. */ + +/* Bitmap directory entry constraints */ +#define BME_MAX_TABLE_SIZE 0x8000000 +#define BME_MAX_PHYS_SIZE 0x20000000 /* restrict BdrvDirtyBitmap size in RAM */ +#define BME_MAX_GRANULARITY_BITS 31 +#define BME_MIN_GRANULARITY_BITS 9 +#define BME_MAX_NAME_SIZE 1023 + +/* Bitmap directory entry flags */ +#define BME_RESERVED_FLAGS 0xfffffffcU + +/* bits [1, 8] U [56, 63] are reserved */ +#define BME_TABLE_ENTRY_RESERVED_MASK 0xff000000000001feULL +#define BME_TABLE_ENTRY_OFFSET_MASK 0x00fffffffffffe00ULL +#define BME_TABLE_ENTRY_FLAG_ALL_ONES (1ULL << 0) + +typedef struct QEMU_PACKED Qcow2BitmapDirEntry { + /* header is 8 byte aligned */ + uint64_t bitmap_table_offset; + + uint32_t bitmap_table_size; + uint32_t flags; + + uint8_t type; + uint8_t granularity_bits; + uint16_t name_size; + uint32_t extra_data_size; + /* extra data follows */ + /* name follows */ +} Qcow2BitmapDirEntry; + +typedef struct Qcow2BitmapTable { + uint64_t offset; + uint32_t size; /* number of 64bit entries */ + QSIMPLEQ_ENTRY(Qcow2BitmapTable) entry; +} Qcow2BitmapTable; + +typedef struct Qcow2Bitmap { + Qcow2BitmapTable table; + uint32_t flags; + uint8_t granularity_bits; + char *name; + + QSIMPLEQ_ENTRY(Qcow2Bitmap) entry; +} Qcow2Bitmap; +typedef QSIMPLEQ_HEAD(Qcow2BitmapList, Qcow2Bitmap) Qcow2BitmapList; + +typedef enum BitmapType { + BT_DIRTY_TRACKING_BITMAP = 1 +} BitmapType; + +static int check_table_entry(uint64_t entry, int cluster_size) +{ + uint64_t offset; + + if (entry & BME_TABLE_ENTRY_RESERVED_MASK) { + return -EINVAL; + } + + offset = entry & BME_TABLE_ENTRY_OFFSET_MASK; + if (offset != 0) { + /* if offset specified, bit 0 is reserved */ + if (entry & BME_TABLE_ENTRY_FLAG_ALL_ONES) { + return -EINVAL; + } + + if (offset % cluster_size != 0) { + return -EINVAL; + } + } + + return 0; +} + +static int bitmap_table_load(BlockDriverState *bs, Qcow2BitmapTable *tb, + uint64_t **bitmap_table) +{ + int ret; + BDRVQcow2State *s = bs->opaque; + uint32_t i; + uint64_t *table; + + assert(tb->size != 0); + table = g_try_new(uint64_t, tb->size); + if (table == NULL) { + return -ENOMEM; + } + + assert(tb->size <= BME_MAX_TABLE_SIZE); + ret = bdrv_pread(bs->file, tb->offset, + table, tb->size * sizeof(uint64_t)); + if (ret < 0) { + goto fail; + } + + for (i = 0; i < tb->size; ++i) { + be64_to_cpus(&table[i]); + ret = check_table_entry(table[i], s->cluster_size); + if (ret < 0) { + goto fail; + } + } + + *bitmap_table = table; + return 0; + +fail: + g_free(table); + + return ret; +} + +/* + * Bitmap List + */ + +/* + * Bitmap List private functions + * Only Bitmap List knows about bitmap directory structure in Qcow2. + */ + +static inline void bitmap_dir_entry_to_cpu(Qcow2BitmapDirEntry *entry) +{ + be64_to_cpus(&entry->bitmap_table_offset); + be32_to_cpus(&entry->bitmap_table_size); + be32_to_cpus(&entry->flags); + be16_to_cpus(&entry->name_size); + be32_to_cpus(&entry->extra_data_size); +} + +static inline int calc_dir_entry_size(size_t name_size, size_t extra_data_size) +{ + return align_offset(sizeof(Qcow2BitmapDirEntry) + + name_size + extra_data_size, 8); +} + +static inline int dir_entry_size(Qcow2BitmapDirEntry *entry) +{ + return calc_dir_entry_size(entry->name_size, entry->extra_data_size); +} + +static inline const char *dir_entry_name_field(Qcow2BitmapDirEntry *entry) +{ + return (const char *)(entry + 1) + entry->extra_data_size; +} + +static inline char *dir_entry_copy_name(Qcow2BitmapDirEntry *entry) +{ + const char *name_field = dir_entry_name_field(entry); + return g_strndup(name_field, entry->name_size); +} + +static inline Qcow2BitmapDirEntry *next_dir_entry(Qcow2BitmapDirEntry *entry) +{ + return (Qcow2BitmapDirEntry *)((uint8_t *)entry + dir_entry_size(entry)); +} + +static int check_dir_entry(BlockDriverState *bs, Qcow2BitmapDirEntry *entry) +{ + BDRVQcow2State *s = bs->opaque; + uint64_t phys_bitmap_bytes; + int64_t len; + + bool fail = (entry->bitmap_table_size == 0) || + (entry->bitmap_table_offset == 0) || + (entry->bitmap_table_offset % s->cluster_size) || + (entry->bitmap_table_size > BME_MAX_TABLE_SIZE) || + (entry->granularity_bits > BME_MAX_GRANULARITY_BITS) || + (entry->granularity_bits < BME_MIN_GRANULARITY_BITS) || + (entry->flags & BME_RESERVED_FLAGS) || + (entry->name_size > BME_MAX_NAME_SIZE) || + (entry->type != BT_DIRTY_TRACKING_BITMAP); + + if (fail) { + return -EINVAL; + } + + phys_bitmap_bytes = (uint64_t)entry->bitmap_table_size * s->cluster_size; + len = bdrv_getlength(bs); + + if (len < 0) { + return len; + } + + fail = (phys_bitmap_bytes > BME_MAX_PHYS_SIZE) || + (len > ((phys_bitmap_bytes * 8) << entry->granularity_bits)); + + return fail ? -EINVAL : 0; +} + +/* + * Bitmap List public functions + */ + +static void bitmap_free(Qcow2Bitmap *bm) +{ + g_free(bm->name); + g_free(bm); +} + +static void bitmap_list_free(Qcow2BitmapList *bm_list) +{ + Qcow2Bitmap *bm; + + if (bm_list == NULL) { + return; + } + + while ((bm = QSIMPLEQ_FIRST(bm_list)) != NULL) { + QSIMPLEQ_REMOVE_HEAD(bm_list, entry); + bitmap_free(bm); + } + + g_free(bm_list); +} + +static Qcow2BitmapList *bitmap_list_new(void) +{ + Qcow2BitmapList *bm_list = g_new(Qcow2BitmapList, 1); + QSIMPLEQ_INIT(bm_list); + + return bm_list; +} + +/* bitmap_list_load + * Get bitmap list from qcow2 image. Actually reads bitmap directory, + * checks it and convert to bitmap list. + */ +static Qcow2BitmapList *bitmap_list_load(BlockDriverState *bs, uint64_t offset, + uint64_t size, Error **errp) +{ + int ret; + BDRVQcow2State *s = bs->opaque; + uint8_t *dir, *dir_end; + Qcow2BitmapDirEntry *e; + uint32_t nb_dir_entries = 0; + Qcow2BitmapList *bm_list = NULL; + + if (size == 0) { + error_setg(errp, "Requested bitmap directory size is zero"); + return NULL; + } + + if (size > QCOW2_MAX_BITMAP_DIRECTORY_SIZE) { + error_setg(errp, "Requested bitmap directory size is too big"); + return NULL; + } + + dir = g_try_malloc(size); + if (dir == NULL) { + error_setg(errp, "Failed to allocate space for bitmap directory"); + return NULL; + } + dir_end = dir + size; + + ret = bdrv_pread(bs->file, offset, dir, size); + if (ret < 0) { + error_setg_errno(errp, -ret, "Failed to read bitmap directory"); + goto fail; + } + + bm_list = bitmap_list_new(); + for (e = (Qcow2BitmapDirEntry *)dir; + e < (Qcow2BitmapDirEntry *)dir_end; + e = next_dir_entry(e)) + { + Qcow2Bitmap *bm; + + if ((uint8_t *)(e + 1) > dir_end) { + goto broken_dir; + } + + if (++nb_dir_entries > s->nb_bitmaps) { + error_setg(errp, "More bitmaps found than specified in header" + " extension"); + goto fail; + } + bitmap_dir_entry_to_cpu(e); + + if ((uint8_t *)next_dir_entry(e) > dir_end) { + goto broken_dir; + } + + if (e->extra_data_size != 0) { + error_setg(errp, "Bitmap extra data is not supported"); + goto fail; + } + + ret = check_dir_entry(bs, e); + if (ret < 0) { + error_setg(errp, "Bitmap '%.*s' doesn't satisfy the constraints", + e->name_size, dir_entry_name_field(e)); + goto fail; + } + + bm = g_new(Qcow2Bitmap, 1); + bm->table.offset = e->bitmap_table_offset; + bm->table.size = e->bitmap_table_size; + bm->flags = e->flags; + bm->granularity_bits = e->granularity_bits; + bm->name = dir_entry_copy_name(e); + QSIMPLEQ_INSERT_TAIL(bm_list, bm, entry); + } + + if (nb_dir_entries != s->nb_bitmaps) { + error_setg(errp, "Less bitmaps found than specified in header" + " extension"); + goto fail; + } + + if ((uint8_t *)e != dir_end) { + goto broken_dir; + } + + g_free(dir); + return bm_list; + +broken_dir: + ret = -EINVAL; + error_setg(errp, "Broken bitmap directory"); + +fail: + g_free(dir); + bitmap_list_free(bm_list); + + return NULL; +} + +int qcow2_check_bitmaps_refcounts(BlockDriverState *bs, BdrvCheckResult *res, + void **refcount_table, + int64_t *refcount_table_size) +{ + int ret; + BDRVQcow2State *s = bs->opaque; + Qcow2BitmapList *bm_list; + Qcow2Bitmap *bm; + + if (s->nb_bitmaps == 0) { + return 0; + } + + ret = qcow2_inc_refcounts_imrt(bs, res, refcount_table, refcount_table_size, + s->bitmap_directory_offset, + s->bitmap_directory_size); + if (ret < 0) { + return ret; + } + + bm_list = bitmap_list_load(bs, s->bitmap_directory_offset, + s->bitmap_directory_size, NULL); + if (bm_list == NULL) { + res->corruptions++; + return -EINVAL; + } + + QSIMPLEQ_FOREACH(bm, bm_list, entry) { + uint64_t *bitmap_table = NULL; + int i; + + ret = qcow2_inc_refcounts_imrt(bs, res, + refcount_table, refcount_table_size, + bm->table.offset, + bm->table.size * sizeof(uint64_t)); + if (ret < 0) { + goto out; + } + + ret = bitmap_table_load(bs, &bm->table, &bitmap_table); + if (ret < 0) { + res->corruptions++; + goto out; + } + + for (i = 0; i < bm->table.size; ++i) { + uint64_t entry = bitmap_table[i]; + uint64_t offset = entry & BME_TABLE_ENTRY_OFFSET_MASK; + + if (check_table_entry(entry, s->cluster_size) < 0) { + res->corruptions++; + continue; + } + + if (offset == 0) { + continue; + } + + ret = qcow2_inc_refcounts_imrt(bs, res, + refcount_table, refcount_table_size, + offset, s->cluster_size); + if (ret < 0) { + g_free(bitmap_table); + goto out; + } + } + + g_free(bitmap_table); + } + +out: + bitmap_list_free(bm_list); + + return ret; +} diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c index 8add3d5640..ceb08bc16f 100644 --- a/block/qcow2-refcount.c +++ b/block/qcow2-refcount.c @@ -1869,6 +1869,12 @@ static int calculate_refcounts(BlockDriverState *bs, BdrvCheckResult *res, } } + /* bitmaps */ + ret = qcow2_check_bitmaps_refcounts(bs, res, refcount_table, nb_clusters); + if (ret < 0) { + return ret; + } + return check_refblocks(bs, res, fix, rebuild, refcount_table, nb_clusters); } diff --git a/block/qcow2.c b/block/qcow2.c index 5339aa0cb1..8688fdd8eb 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -67,6 +67,7 @@ typedef struct { #define QCOW2_EXT_MAGIC_BACKING_FORMAT 0xE2792ACA #define QCOW2_EXT_MAGIC_FEATURE_TABLE 0x6803f857 #define QCOW2_EXT_MAGIC_CRYPTO_HEADER 0x0537be77 +#define QCOW2_EXT_MAGIC_BITMAPS 0x23852875 static int qcow2_probe(const uint8_t *buf, int buf_size, const char *filename) { @@ -170,12 +171,18 @@ static ssize_t qcow2_crypto_hdr_write_func(QCryptoBlock *block, size_t offset, */ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset, uint64_t end_offset, void **p_feature_table, - int flags, Error **errp) + int flags, bool *need_update_header, + Error **errp) { BDRVQcow2State *s = bs->opaque; QCowExtension ext; uint64_t offset; int ret; + Qcow2BitmapHeaderExt bitmaps_ext; + + if (need_update_header != NULL) { + *need_update_header = false; + } #ifdef DEBUG_EXT printf("qcow2_read_extensions: start=%ld end=%ld\n", start_offset, end_offset); @@ -287,6 +294,85 @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset, } } break; + case QCOW2_EXT_MAGIC_BITMAPS: + if (ext.len != sizeof(bitmaps_ext)) { + error_setg_errno(errp, -ret, "bitmaps_ext: " + "Invalid extension length"); + return -EINVAL; + } + + if (!(s->autoclear_features & QCOW2_AUTOCLEAR_BITMAPS)) { + error_report("WARNING: a program lacking bitmap support " + "modified this file, so all bitmaps are now " + "considered inconsistent. Some clusters may be " + "leaked, run 'qemu-img check -r' on the image " + "file to fix."); + if (need_update_header != NULL) { + /* Updating is needed to drop invalid bitmap extension. */ + *need_update_header = true; + } + break; + } + + ret = bdrv_pread(bs->file, offset, &bitmaps_ext, ext.len); + if (ret < 0) { + error_setg_errno(errp, -ret, "bitmaps_ext: " + "Could not read ext header"); + return ret; + } + + if (bitmaps_ext.reserved32 != 0) { + error_setg_errno(errp, -ret, "bitmaps_ext: " + "Reserved field is not zero"); + return -EINVAL; + } + + be32_to_cpus(&bitmaps_ext.nb_bitmaps); + be64_to_cpus(&bitmaps_ext.bitmap_directory_size); + be64_to_cpus(&bitmaps_ext.bitmap_directory_offset); + + if (bitmaps_ext.nb_bitmaps > QCOW2_MAX_BITMAPS) { + error_setg(errp, + "bitmaps_ext: Image has %" PRIu32 " bitmaps, " + "exceeding the QEMU supported maximum of %d", + bitmaps_ext.nb_bitmaps, QCOW2_MAX_BITMAPS); + return -EINVAL; + } + + if (bitmaps_ext.nb_bitmaps == 0) { + error_setg(errp, "found bitmaps extension with zero bitmaps"); + return -EINVAL; + } + + if (bitmaps_ext.bitmap_directory_offset & (s->cluster_size - 1)) { + error_setg(errp, "bitmaps_ext: " + "invalid bitmap directory offset"); + return -EINVAL; + } + + if (bitmaps_ext.bitmap_directory_size > + QCOW2_MAX_BITMAP_DIRECTORY_SIZE) { + error_setg(errp, "bitmaps_ext: " + "bitmap directory size (%" PRIu64 ") exceeds " + "the maximum supported size (%d)", + bitmaps_ext.bitmap_directory_size, + QCOW2_MAX_BITMAP_DIRECTORY_SIZE); + return -EINVAL; + } + + s->nb_bitmaps = bitmaps_ext.nb_bitmaps; + s->bitmap_directory_offset = + bitmaps_ext.bitmap_directory_offset; + s->bitmap_directory_size = + bitmaps_ext.bitmap_directory_size; + +#ifdef DEBUG_EXT + printf("Qcow2: Got bitmaps extension: " + "offset=%" PRIu64 " nb_bitmaps=%" PRIu32 "\n", + s->bitmap_directory_offset, s->nb_bitmaps); +#endif + break; + default: /* unknown magic - save it in case we need to rewrite the header */ { @@ -1008,6 +1094,7 @@ static int qcow2_do_open(BlockDriverState *bs, QDict *options, int flags, Error *local_err = NULL; uint64_t ext_end; uint64_t l1_vm_state_index; + bool update_header = false; ret = bdrv_pread(bs->file, 0, &header, sizeof(header)); if (ret < 0) { @@ -1113,7 +1200,7 @@ static int qcow2_do_open(BlockDriverState *bs, QDict *options, int flags, if (s->incompatible_features & ~QCOW2_INCOMPAT_MASK) { void *feature_table = NULL; qcow2_read_extensions(bs, header.header_length, ext_end, - &feature_table, flags, NULL); + &feature_table, flags, NULL, NULL); report_unsupported_feature(errp, feature_table, s->incompatible_features & ~QCOW2_INCOMPAT_MASK); @@ -1297,7 +1384,7 @@ static int qcow2_do_open(BlockDriverState *bs, QDict *options, int flags, /* read qcow2 extensions */ if (qcow2_read_extensions(bs, header.header_length, ext_end, NULL, - flags, &local_err)) { + flags, &update_header, &local_err)) { error_propagate(errp, local_err); ret = -EINVAL; goto fail; @@ -1357,8 +1444,10 @@ static int qcow2_do_open(BlockDriverState *bs, QDict *options, int flags, } /* Clear unknown autoclear feature bits */ - if (!bs->read_only && !(flags & BDRV_O_INACTIVE) && s->autoclear_features) { - s->autoclear_features = 0; + update_header |= s->autoclear_features & ~QCOW2_AUTOCLEAR_MASK; + + if (update_header && !bs->read_only && !(flags & BDRV_O_INACTIVE)) { + s->autoclear_features &= QCOW2_AUTOCLEAR_MASK; ret = qcow2_update_header(bs); if (ret < 0) { error_setg_errno(errp, -ret, "Could not update qcow2 header"); @@ -2203,6 +2292,25 @@ int qcow2_update_header(BlockDriverState *bs) buflen -= ret; } + /* Bitmap extension */ + if (s->nb_bitmaps > 0) { + Qcow2BitmapHeaderExt bitmaps_header = { + .nb_bitmaps = cpu_to_be32(s->nb_bitmaps), + .bitmap_directory_size = + cpu_to_be64(s->bitmap_directory_size), + .bitmap_directory_offset = + cpu_to_be64(s->bitmap_directory_offset) + }; + ret = header_ext_add(buf, QCOW2_EXT_MAGIC_BITMAPS, + &bitmaps_header, sizeof(bitmaps_header), + buflen); + if (ret < 0) { + goto fail; + } + buf += ret; + buflen -= ret; + } + /* Keep unknown header extensions */ QLIST_FOREACH(uext, &s->unknown_header_ext, next) { ret = header_ext_add(buf, uext->magic, uext->data, uext->len, buflen); @@ -2884,6 +2992,13 @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset, Error **errp) return -ENOTSUP; } + /* cannot proceed if image has bitmaps */ + if (s->nb_bitmaps) { + /* TODO: resize bitmaps in the image */ + error_setg(errp, "Can't resize an image which has bitmaps"); + return -ENOTSUP; + } + /* shrinking is currently not supported */ if (offset < bs->total_sectors * 512) { error_setg(errp, "qcow2 doesn't support shrinking images yet"); diff --git a/block/qcow2.h b/block/qcow2.h index a272a39ab2..348864860b 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -53,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) */ @@ -201,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, @@ -228,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; @@ -274,6 +293,10 @@ typedef struct BDRVQcow2State { 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; @@ -618,4 +641,8 @@ 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); #endif From 8bfc932e1eaab86788bb08207d520bd2804422ae Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 28 Jun 2017 15:05:09 +0300 Subject: [PATCH 31/85] block/dirty-bitmap: fix comment for BlockDirtyBitmap.disabled field Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: John Snow Reviewed-by: Max Reitz Message-id: 20170628120530.31251-10-vsementsov@virtuozzo.com Signed-off-by: Max Reitz --- block/dirty-bitmap.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c index f502c45a70..a8fe149c4a 100644 --- a/block/dirty-bitmap.c +++ b/block/dirty-bitmap.c @@ -43,7 +43,8 @@ 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 */ QLIST_ENTRY(BdrvDirtyBitmap) list; }; From d6883bc96890dae97757ee8a61aab7f18d9a66de Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 28 Jun 2017 15:05:10 +0300 Subject: [PATCH 32/85] block/dirty-bitmap: add readonly field to BdrvDirtyBitmap It will be needed in following commits for persistent bitmaps. If bitmap is loaded from read-only storage (and we can't mark it "in use" in this storage) corresponding BdrvDirtyBitmap should be read-only. Signed-off-by: Vladimir Sementsov-Ogievskiy Message-id: 20170628120530.31251-11-vsementsov@virtuozzo.com Signed-off-by: Max Reitz --- block/dirty-bitmap.c | 36 ++++++++++++++++++++++++++++++++++++ block/io.c | 8 ++++++++ blockdev.c | 6 ++++++ include/block/dirty-bitmap.h | 4 ++++ 4 files changed, 54 insertions(+) diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c index a8fe149c4a..17d3068336 100644 --- a/block/dirty-bitmap.c +++ b/block/dirty-bitmap.c @@ -46,6 +46,12 @@ struct BdrvDirtyBitmap { 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. */ QLIST_ENTRY(BdrvDirtyBitmap) list; }; @@ -505,6 +511,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); } @@ -521,6 +528,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); } @@ -535,6 +543,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); @@ -551,6 +560,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); } @@ -613,6 +623,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); @@ -635,3 +646,28 @@ 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; +} diff --git a/block/io.c b/block/io.c index 23170a57ee..b413727524 100644 --- a/block/io.c +++ b/block/io.c @@ -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; diff --git a/blockdev.c b/blockdev.c index 92c59910fc..edeb36bd3b 100644 --- a/blockdev.c +++ b/blockdev.c @@ -2033,6 +2033,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); @@ -2779,6 +2782,9 @@ 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); diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h index 05451c727d..cb43fa37e2 100644 --- a/include/block/dirty-bitmap.h +++ b/include/block/dirty-bitmap.h @@ -71,6 +71,8 @@ void bdrv_dirty_bitmap_deserialize_ones(BdrvDirtyBitmap *bitmap, bool finish); void bdrv_dirty_bitmap_deserialize_finish(BdrvDirtyBitmap *bitmap); +void bdrv_dirty_bitmap_set_readonly(BdrvDirtyBitmap *bitmap, bool value); + /* Functions that require manual locking. */ void bdrv_dirty_bitmap_lock(BdrvDirtyBitmap *bitmap); void bdrv_dirty_bitmap_unlock(BdrvDirtyBitmap *bitmap); @@ -85,5 +87,7 @@ 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); #endif From d1258dd0c87d27faa5d25f8d604e030dd2a5d3d7 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 28 Jun 2017 15:05:11 +0300 Subject: [PATCH 33/85] qcow2: autoloading dirty bitmaps Auto loading bitmaps are bitmaps in Qcow2, with the AUTO flag set. They are loaded when the image is opened and become BdrvDirtyBitmaps for the corresponding drive. Extra data in bitmaps is not supported for now. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Max Reitz Reviewed-by: John Snow Message-id: 20170628120530.31251-12-vsementsov@virtuozzo.com Signed-off-by: Max Reitz --- block/qcow2-bitmap.c | 389 +++++++++++++++++++++++++++++++++++++++++++ block/qcow2.c | 17 +- block/qcow2.h | 2 + 3 files changed, 406 insertions(+), 2 deletions(-) diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c index b8e472b3e8..2c7b057e21 100644 --- a/block/qcow2-bitmap.c +++ b/block/qcow2-bitmap.c @@ -44,6 +44,8 @@ /* Bitmap directory entry flags */ #define BME_RESERVED_FLAGS 0xfffffffcU +#define BME_FLAG_IN_USE (1U << 0) +#define BME_FLAG_AUTO (1U << 1) /* bits [1, 8] U [56, 63] are reserved */ #define BME_TABLE_ENTRY_RESERVED_MASK 0xff000000000001feULL @@ -85,6 +87,23 @@ typedef enum BitmapType { BT_DIRTY_TRACKING_BITMAP = 1 } BitmapType; +static inline bool can_write(BlockDriverState *bs) +{ + return !bdrv_is_read_only(bs) && !(bdrv_get_flags(bs) & BDRV_O_INACTIVE); +} + +static int update_header_sync(BlockDriverState *bs) +{ + int ret; + + ret = qcow2_update_header(bs); + if (ret < 0) { + return ret; + } + + return bdrv_flush(bs); +} + static int check_table_entry(uint64_t entry, int cluster_size) { uint64_t offset; @@ -146,6 +165,120 @@ fail: return ret; } +/* This function returns the number of disk sectors covered by a single qcow2 + * cluster of bitmap data. */ +static uint64_t sectors_covered_by_bitmap_cluster(const BDRVQcow2State *s, + const BdrvDirtyBitmap *bitmap) +{ + uint32_t sector_granularity = + bdrv_dirty_bitmap_granularity(bitmap) >> BDRV_SECTOR_BITS; + + return (uint64_t)sector_granularity * (s->cluster_size << 3); +} + +/* load_bitmap_data + * @bitmap_table entries must satisfy specification constraints. + * @bitmap must be cleared */ +static int load_bitmap_data(BlockDriverState *bs, + const uint64_t *bitmap_table, + uint32_t bitmap_table_size, + BdrvDirtyBitmap *bitmap) +{ + int ret = 0; + BDRVQcow2State *s = bs->opaque; + uint64_t sector, sbc; + uint64_t bm_size = bdrv_dirty_bitmap_size(bitmap); + uint8_t *buf = NULL; + uint64_t i, tab_size = + size_to_clusters(s, + bdrv_dirty_bitmap_serialization_size(bitmap, 0, bm_size)); + + if (tab_size != bitmap_table_size || tab_size > BME_MAX_TABLE_SIZE) { + return -EINVAL; + } + + buf = g_malloc(s->cluster_size); + sbc = sectors_covered_by_bitmap_cluster(s, bitmap); + for (i = 0, sector = 0; i < tab_size; ++i, sector += sbc) { + uint64_t count = MIN(bm_size - sector, sbc); + uint64_t entry = bitmap_table[i]; + uint64_t offset = entry & BME_TABLE_ENTRY_OFFSET_MASK; + + assert(check_table_entry(entry, s->cluster_size) == 0); + + if (offset == 0) { + if (entry & BME_TABLE_ENTRY_FLAG_ALL_ONES) { + bdrv_dirty_bitmap_deserialize_ones(bitmap, sector, count, + false); + } else { + /* No need to deserialize zeros because the dirty bitmap is + * already cleared */ + } + } else { + ret = bdrv_pread(bs->file, offset, buf, s->cluster_size); + if (ret < 0) { + goto finish; + } + bdrv_dirty_bitmap_deserialize_part(bitmap, buf, sector, count, + false); + } + } + ret = 0; + + bdrv_dirty_bitmap_deserialize_finish(bitmap); + +finish: + g_free(buf); + + return ret; +} + +static BdrvDirtyBitmap *load_bitmap(BlockDriverState *bs, + Qcow2Bitmap *bm, Error **errp) +{ + int ret; + uint64_t *bitmap_table = NULL; + uint32_t granularity; + BdrvDirtyBitmap *bitmap = NULL; + + if (bm->flags & BME_FLAG_IN_USE) { + error_setg(errp, "Bitmap '%s' is in use", bm->name); + goto fail; + } + + ret = bitmap_table_load(bs, &bm->table, &bitmap_table); + if (ret < 0) { + error_setg_errno(errp, -ret, + "Could not read bitmap_table table from image for " + "bitmap '%s'", bm->name); + goto fail; + } + + granularity = 1U << bm->granularity_bits; + bitmap = bdrv_create_dirty_bitmap(bs, granularity, bm->name, errp); + if (bitmap == NULL) { + goto fail; + } + + ret = load_bitmap_data(bs, bitmap_table, bm->table.size, bitmap); + if (ret < 0) { + error_setg_errno(errp, -ret, "Could not read bitmap '%s' from image", + bm->name); + goto fail; + } + + g_free(bitmap_table); + return bitmap; + +fail: + g_free(bitmap_table); + if (bitmap != NULL) { + bdrv_release_dirty_bitmap(bs, bitmap); + } + + return NULL; +} + /* * Bitmap List */ @@ -164,6 +297,15 @@ static inline void bitmap_dir_entry_to_cpu(Qcow2BitmapDirEntry *entry) be32_to_cpus(&entry->extra_data_size); } +static inline void bitmap_dir_entry_to_be(Qcow2BitmapDirEntry *entry) +{ + cpu_to_be64s(&entry->bitmap_table_offset); + cpu_to_be32s(&entry->bitmap_table_size); + cpu_to_be32s(&entry->flags); + cpu_to_be16s(&entry->name_size); + cpu_to_be32s(&entry->extra_data_size); +} + static inline int calc_dir_entry_size(size_t name_size, size_t extra_data_size) { return align_offset(sizeof(Qcow2BitmapDirEntry) + @@ -224,6 +366,17 @@ static int check_dir_entry(BlockDriverState *bs, Qcow2BitmapDirEntry *entry) return fail ? -EINVAL : 0; } +static inline void bitmap_directory_to_be(uint8_t *dir, size_t size) +{ + uint8_t *end = dir + size; + while (dir < end) { + Qcow2BitmapDirEntry *e = (Qcow2BitmapDirEntry *)dir; + dir += dir_entry_size(e); + + bitmap_dir_entry_to_be(e); + } +} + /* * Bitmap List public functions */ @@ -258,6 +411,18 @@ static Qcow2BitmapList *bitmap_list_new(void) return bm_list; } +static uint32_t bitmap_list_count(Qcow2BitmapList *bm_list) +{ + Qcow2Bitmap *bm; + uint32_t nb_bitmaps = 0; + + QSIMPLEQ_FOREACH(bm, bm_list, entry) { + nb_bitmaps++; + } + + return nb_bitmaps; +} + /* bitmap_list_load * Get bitmap list from qcow2 image. Actually reads bitmap directory, * checks it and convert to bitmap list. @@ -437,3 +602,227 @@ out: return ret; } + +/* bitmap_list_store + * Store bitmap list to qcow2 image as a bitmap directory. + * Everything is checked. + */ +static int bitmap_list_store(BlockDriverState *bs, Qcow2BitmapList *bm_list, + uint64_t *offset, uint64_t *size, bool in_place) +{ + int ret; + uint8_t *dir; + int64_t dir_offset = 0; + uint64_t dir_size = 0; + Qcow2Bitmap *bm; + Qcow2BitmapDirEntry *e; + + QSIMPLEQ_FOREACH(bm, bm_list, entry) { + dir_size += calc_dir_entry_size(strlen(bm->name), 0); + } + + if (dir_size == 0 || dir_size > QCOW2_MAX_BITMAP_DIRECTORY_SIZE) { + return -EINVAL; + } + + if (in_place) { + if (*size != dir_size || *offset == 0) { + return -EINVAL; + } + + dir_offset = *offset; + } + + dir = g_try_malloc(dir_size); + if (dir == NULL) { + return -ENOMEM; + } + + e = (Qcow2BitmapDirEntry *)dir; + QSIMPLEQ_FOREACH(bm, bm_list, entry) { + e->bitmap_table_offset = bm->table.offset; + e->bitmap_table_size = bm->table.size; + e->flags = bm->flags; + e->type = BT_DIRTY_TRACKING_BITMAP; + e->granularity_bits = bm->granularity_bits; + e->name_size = strlen(bm->name); + e->extra_data_size = 0; + memcpy(e + 1, bm->name, e->name_size); + + if (check_dir_entry(bs, e) < 0) { + ret = -EINVAL; + goto fail; + } + + e = next_dir_entry(e); + } + + bitmap_directory_to_be(dir, dir_size); + + if (!in_place) { + dir_offset = qcow2_alloc_clusters(bs, dir_size); + if (dir_offset < 0) { + ret = dir_offset; + goto fail; + } + } + + ret = qcow2_pre_write_overlap_check(bs, 0, dir_offset, dir_size); + if (ret < 0) { + goto fail; + } + + ret = bdrv_pwrite(bs->file, dir_offset, dir, dir_size); + if (ret < 0) { + goto fail; + } + + g_free(dir); + + if (!in_place) { + *size = dir_size; + *offset = dir_offset; + } + + return 0; + +fail: + g_free(dir); + + if (!in_place && dir_offset > 0) { + qcow2_free_clusters(bs, dir_offset, dir_size, QCOW2_DISCARD_OTHER); + } + + return ret; +} + +/* + * Bitmap List end + */ + +static int update_ext_header_and_dir_in_place(BlockDriverState *bs, + Qcow2BitmapList *bm_list) +{ + BDRVQcow2State *s = bs->opaque; + int ret; + + if (!(s->autoclear_features & QCOW2_AUTOCLEAR_BITMAPS) || + bm_list == NULL || QSIMPLEQ_EMPTY(bm_list) || + bitmap_list_count(bm_list) != s->nb_bitmaps) + { + return -EINVAL; + } + + s->autoclear_features &= ~(uint64_t)QCOW2_AUTOCLEAR_BITMAPS; + ret = update_header_sync(bs); + if (ret < 0) { + /* Two variants are possible here: + * 1. Autoclear flag is dropped, all bitmaps will be lost. + * 2. Autoclear flag is not dropped, old state is left. + */ + return ret; + } + + /* autoclear bit is not set, so we can safely update bitmap directory */ + + ret = bitmap_list_store(bs, bm_list, &s->bitmap_directory_offset, + &s->bitmap_directory_size, true); + if (ret < 0) { + /* autoclear bit is cleared, so all leaked clusters would be removed on + * qemu-img check */ + return ret; + } + + ret = update_header_sync(bs); + if (ret < 0) { + /* autoclear bit is cleared, so all leaked clusters would be removed on + * qemu-img check */ + return ret; + } + + s->autoclear_features |= QCOW2_AUTOCLEAR_BITMAPS; + return update_header_sync(bs); + /* If final update_header_sync() fails, two variants are possible: + * 1. Autoclear flag is not set, all bitmaps will be lost. + * 2. Autoclear flag is set, header and directory are successfully updated. + */ +} + +/* for g_slist_foreach for GSList of BdrvDirtyBitmap* elements */ +static void release_dirty_bitmap_helper(gpointer bitmap, + gpointer bs) +{ + bdrv_release_dirty_bitmap(bs, bitmap); +} + +/* for g_slist_foreach for GSList of BdrvDirtyBitmap* elements */ +static void set_readonly_helper(gpointer bitmap, gpointer value) +{ + bdrv_dirty_bitmap_set_readonly(bitmap, (bool)value); +} + +/* qcow2_load_autoloading_dirty_bitmaps() + * Return value is a hint for caller: true means that the Qcow2 header was + * updated. (false doesn't mean that the header should be updated by the + * caller, it just means that updating was not needed or the image cannot be + * written to). + * On failure the function returns false. + */ +bool qcow2_load_autoloading_dirty_bitmaps(BlockDriverState *bs, Error **errp) +{ + BDRVQcow2State *s = bs->opaque; + Qcow2BitmapList *bm_list; + Qcow2Bitmap *bm; + GSList *created_dirty_bitmaps = NULL; + bool header_updated = false; + + if (s->nb_bitmaps == 0) { + /* No bitmaps - nothing to do */ + return false; + } + + bm_list = bitmap_list_load(bs, s->bitmap_directory_offset, + s->bitmap_directory_size, errp); + if (bm_list == NULL) { + return false; + } + + QSIMPLEQ_FOREACH(bm, bm_list, entry) { + if ((bm->flags & BME_FLAG_AUTO) && !(bm->flags & BME_FLAG_IN_USE)) { + BdrvDirtyBitmap *bitmap = load_bitmap(bs, bm, errp); + if (bitmap == NULL) { + goto fail; + } + bm->flags |= BME_FLAG_IN_USE; + created_dirty_bitmaps = + g_slist_append(created_dirty_bitmaps, bitmap); + } + } + + if (created_dirty_bitmaps != NULL) { + if (can_write(bs)) { + /* in_use flags must be updated */ + int ret = update_ext_header_and_dir_in_place(bs, bm_list); + if (ret < 0) { + error_setg_errno(errp, -ret, "Can't update bitmap directory"); + goto fail; + } + header_updated = true; + } else { + g_slist_foreach(created_dirty_bitmaps, set_readonly_helper, + (gpointer)true); + } + } + + g_slist_free(created_dirty_bitmaps); + bitmap_list_free(bm_list); + + return header_updated; + +fail: + g_slist_foreach(created_dirty_bitmaps, release_dirty_bitmap_helper, bs); + g_slist_free(created_dirty_bitmaps); + bitmap_list_free(bm_list); + + return false; +} diff --git a/block/qcow2.c b/block/qcow2.c index 8688fdd8eb..8645b08fd3 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -1445,9 +1445,22 @@ static int qcow2_do_open(BlockDriverState *bs, QDict *options, int flags, /* Clear unknown autoclear feature bits */ update_header |= s->autoclear_features & ~QCOW2_AUTOCLEAR_MASK; - - if (update_header && !bs->read_only && !(flags & BDRV_O_INACTIVE)) { + update_header = + update_header && !bs->read_only && !(flags & BDRV_O_INACTIVE); + if (update_header) { s->autoclear_features &= QCOW2_AUTOCLEAR_MASK; + } + + if (qcow2_load_autoloading_dirty_bitmaps(bs, &local_err)) { + update_header = false; + } + if (local_err != NULL) { + error_propagate(errp, local_err); + ret = -EINVAL; + goto fail; + } + + if (update_header) { ret = qcow2_update_header(bs); if (ret < 0) { error_setg_errno(errp, -ret, "Could not update qcow2 header"); diff --git a/block/qcow2.h b/block/qcow2.h index 348864860b..886480b018 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -645,4 +645,6 @@ void qcow2_cache_put(BlockDriverState *bs, Qcow2Cache *c, void **table); 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); + #endif From 50bf65bab69aa6d01f759732927fbbf1c8abfe15 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 28 Jun 2017 15:05:12 +0300 Subject: [PATCH 34/85] block: refactor bdrv_reopen_commit Add bs local variable to simplify code. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: John Snow Message-id: 20170628120530.31251-13-vsementsov@virtuozzo.com Signed-off-by: Max Reitz --- block.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/block.c b/block.c index b9e5114a27..15a4e75ff5 100644 --- a/block.c +++ b/block.c @@ -2982,9 +2982,11 @@ error: void bdrv_reopen_commit(BDRVReopenState *reopen_state) { BlockDriver *drv; + BlockDriverState *bs; assert(reopen_state != NULL); - drv = reopen_state->bs->drv; + bs = reopen_state->bs; + drv = bs->drv; assert(drv != NULL); /* If there are any driver level actions to take */ @@ -2993,13 +2995,13 @@ void bdrv_reopen_commit(BDRVReopenState *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); } /* From cb9ff6c25a25179736b7d8d9ddf00d45e5112a2b Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 28 Jun 2017 15:05:13 +0300 Subject: [PATCH 35/85] block: new bdrv_reopen_bitmaps_rw interface Add format driver handler, which should mark loaded read-only bitmaps as 'IN_USE' in the image and unset read_only field in corresponding BdrvDirtyBitmap's. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: John Snow Reviewed-by: Max Reitz Message-id: 20170628120530.31251-14-vsementsov@virtuozzo.com Signed-off-by: Max Reitz --- block.c | 19 +++++++++++++++++++ include/block/block_int.h | 7 +++++++ 2 files changed, 26 insertions(+) diff --git a/block.c b/block.c index 15a4e75ff5..3ec6624cb7 100644 --- a/block.c +++ b/block.c @@ -2983,12 +2983,16 @@ void bdrv_reopen_commit(BDRVReopenState *reopen_state) { BlockDriver *drv; BlockDriverState *bs; + bool old_can_write, new_can_write; assert(reopen_state != NULL); 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); @@ -3002,6 +3006,21 @@ void bdrv_reopen_commit(BDRVReopenState *reopen_state) bs->read_only = !(reopen_state->flags & BDRV_O_RDWR); 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)); + } + } } /* diff --git a/include/block/block_int.h b/include/block/block_int.h index b9069c514f..254f860972 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -381,6 +381,13 @@ 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); + QLIST_ENTRY(BlockDriver) list; }; From 1b6b0562dbf28dcae8faa02ac09a93e6623dd5d2 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 28 Jun 2017 15:05:14 +0300 Subject: [PATCH 36/85] qcow2: support .bdrv_reopen_bitmaps_rw Realize bdrv_reopen_bitmaps_rw interface. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: John Snow Reviewed-by: Max Reitz Message-id: 20170628120530.31251-15-vsementsov@virtuozzo.com Signed-off-by: Max Reitz --- block/qcow2-bitmap.c | 61 ++++++++++++++++++++++++++++++++++++++++++++ block/qcow2.c | 2 ++ block/qcow2.h | 1 + 3 files changed, 64 insertions(+) diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c index 2c7b057e21..a21fab8ce8 100644 --- a/block/qcow2-bitmap.c +++ b/block/qcow2-bitmap.c @@ -826,3 +826,64 @@ fail: return false; } + +int qcow2_reopen_bitmaps_rw(BlockDriverState *bs, Error **errp) +{ + BDRVQcow2State *s = bs->opaque; + Qcow2BitmapList *bm_list; + Qcow2Bitmap *bm; + GSList *ro_dirty_bitmaps = NULL; + int ret = 0; + + if (s->nb_bitmaps == 0) { + /* No bitmaps - nothing to do */ + return 0; + } + + if (!can_write(bs)) { + error_setg(errp, "Can't write to the image on reopening bitmaps rw"); + return -EINVAL; + } + + bm_list = bitmap_list_load(bs, s->bitmap_directory_offset, + s->bitmap_directory_size, errp); + if (bm_list == NULL) { + return -EINVAL; + } + + QSIMPLEQ_FOREACH(bm, bm_list, entry) { + if (!(bm->flags & BME_FLAG_IN_USE)) { + BdrvDirtyBitmap *bitmap = bdrv_find_dirty_bitmap(bs, bm->name); + if (bitmap == NULL) { + continue; + } + + if (!bdrv_dirty_bitmap_readonly(bitmap)) { + error_setg(errp, "Bitmap %s is not readonly but not marked" + "'IN_USE' in the image. Something went wrong," + "all the bitmaps may be corrupted", bm->name); + ret = -EINVAL; + goto out; + } + + bm->flags |= BME_FLAG_IN_USE; + ro_dirty_bitmaps = g_slist_append(ro_dirty_bitmaps, bitmap); + } + } + + if (ro_dirty_bitmaps != NULL) { + /* in_use flags must be updated */ + ret = update_ext_header_and_dir_in_place(bs, bm_list); + if (ret < 0) { + error_setg_errno(errp, -ret, "Can't update bitmap directory"); + goto out; + } + g_slist_foreach(ro_dirty_bitmaps, set_readonly_helper, false); + } + +out: + g_slist_free(ro_dirty_bitmaps); + bitmap_list_free(bm_list); + + return ret; +} diff --git a/block/qcow2.c b/block/qcow2.c index 8645b08fd3..19cc49a85b 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -3973,6 +3973,8 @@ BlockDriver bdrv_qcow2 = { .bdrv_detach_aio_context = qcow2_detach_aio_context, .bdrv_attach_aio_context = qcow2_attach_aio_context, + + .bdrv_reopen_bitmaps_rw = qcow2_reopen_bitmaps_rw, }; static void bdrv_qcow2_init(void) diff --git a/block/qcow2.h b/block/qcow2.h index 886480b018..633bd43841 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -646,5 +646,6 @@ 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); #endif From a0319aacd4f5356119c23657df640049777f038c Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 28 Jun 2017 15:05:15 +0300 Subject: [PATCH 37/85] block/dirty-bitmap: add autoload field to BdrvDirtyBitmap Mirror AUTO flag from Qcow2 bitmap in BdrvDirtyBitmap. This will be needed in future, to save this flag back to Qcow2 for persistent bitmaps. Signed-off-by: Vladimir Sementsov-Ogievskiy Message-id: 20170628120530.31251-16-vsementsov@virtuozzo.com Signed-off-by: Max Reitz --- block/dirty-bitmap.c | 18 ++++++++++++++++++ block/qcow2-bitmap.c | 2 ++ include/block/dirty-bitmap.h | 2 ++ 3 files changed, 22 insertions(+) diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c index 17d3068336..06dc7a3ac9 100644 --- a/block/dirty-bitmap.c +++ b/block/dirty-bitmap.c @@ -52,6 +52,8 @@ struct BdrvDirtyBitmap { 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 */ QLIST_ENTRY(BdrvDirtyBitmap) list; }; @@ -100,6 +102,7 @@ void bdrv_dirty_bitmap_make_anon(BdrvDirtyBitmap *bitmap) assert(!bdrv_dirty_bitmap_frozen(bitmap)); g_free(bitmap->name); bitmap->name = NULL; + bitmap->autoload = false; } /* Called with BQL taken. */ @@ -296,6 +299,8 @@ BdrvDirtyBitmap *bdrv_dirty_bitmap_abdicate(BlockDriverState *bs, bitmap->name = NULL; successor->name = name; bitmap->successor = NULL; + successor->autoload = bitmap->autoload; + bitmap->autoload = false; bdrv_release_dirty_bitmap(bs, bitmap); return successor; @@ -671,3 +676,16 @@ bool bdrv_has_readonly_bitmaps(BlockDriverState *bs) 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; +} diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c index a21fab8ce8..ee6d8f75a9 100644 --- a/block/qcow2-bitmap.c +++ b/block/qcow2-bitmap.c @@ -793,6 +793,8 @@ bool qcow2_load_autoloading_dirty_bitmaps(BlockDriverState *bs, Error **errp) if (bitmap == NULL) { goto fail; } + + bdrv_dirty_bitmap_set_autoload(bitmap, true); bm->flags |= BME_FLAG_IN_USE; created_dirty_bitmaps = g_slist_append(created_dirty_bitmaps, bitmap); diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h index cb43fa37e2..e2fea12b94 100644 --- a/include/block/dirty-bitmap.h +++ b/include/block/dirty-bitmap.h @@ -72,6 +72,7 @@ void bdrv_dirty_bitmap_deserialize_ones(BdrvDirtyBitmap *bitmap, 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); /* Functions that require manual locking. */ void bdrv_dirty_bitmap_lock(BdrvDirtyBitmap *bitmap); @@ -89,5 +90,6 @@ 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); #endif From cca43ae1e1a5e2faf42d2db778edc8e76e10dc47 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 28 Jun 2017 15:05:16 +0300 Subject: [PATCH 38/85] block: bdrv_close: release bitmaps after drv->bdrv_close Release bitmaps after 'if (bs->drv) { ... }' block. This will allow format driver to save persistent bitmaps, which will appear in following commits. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Max Reitz Message-id: 20170628120530.31251-17-vsementsov@virtuozzo.com Signed-off-by: Max Reitz --- block.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/block.c b/block.c index 3ec6624cb7..700431d5e9 100644 --- a/block.c +++ b/block.c @@ -3054,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; @@ -3094,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); } From a88b179fdbc68e00ae5eacd49e1bccad32440b5a Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 28 Jun 2017 15:05:17 +0300 Subject: [PATCH 39/85] block: introduce persistent dirty bitmaps New field BdrvDirtyBitmap.persistent means, that bitmap should be saved by format driver in .bdrv_close and .bdrv_inactivate. No format driver supports it for now. Signed-off-by: Vladimir Sementsov-Ogievskiy Message-id: 20170628120530.31251-18-vsementsov@virtuozzo.com [mreitz: Fixed indentation] Signed-off-by: Max Reitz --- block/dirty-bitmap.c | 29 +++++++++++++++++++++++++++++ block/qcow2-bitmap.c | 1 + include/block/dirty-bitmap.h | 4 ++++ 3 files changed, 34 insertions(+) diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c index 06dc7a3ac9..3c17c452ae 100644 --- a/block/dirty-bitmap.c +++ b/block/dirty-bitmap.c @@ -54,6 +54,7 @@ struct BdrvDirtyBitmap { 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; }; @@ -102,6 +103,7 @@ 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; } @@ -299,6 +301,8 @@ 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); @@ -689,3 +693,28 @@ 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; +} diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c index ee6d8f75a9..52e4616b8c 100644 --- a/block/qcow2-bitmap.c +++ b/block/qcow2-bitmap.c @@ -794,6 +794,7 @@ bool qcow2_load_autoloading_dirty_bitmaps(BlockDriverState *bs, Error **errp) goto fail; } + bdrv_dirty_bitmap_set_persistance(bitmap, true); bdrv_dirty_bitmap_set_autoload(bitmap, true); bm->flags |= BME_FLAG_IN_USE; created_dirty_bitmaps = diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h index e2fea12b94..bdf43df694 100644 --- a/include/block/dirty-bitmap.h +++ b/include/block/dirty-bitmap.h @@ -73,6 +73,8 @@ 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); @@ -91,5 +93,7 @@ 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); #endif From 3dd10a06d173e0904c6d47ced1de67c40139d5b1 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 28 Jun 2017 15:05:18 +0300 Subject: [PATCH 40/85] block/dirty-bitmap: add bdrv_dirty_bitmap_next() Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Max Reitz Reviewed-by: John Snow Message-id: 20170628120530.31251-19-vsementsov@virtuozzo.com Signed-off-by: Max Reitz --- block/dirty-bitmap.c | 7 +++++++ include/block/dirty-bitmap.h | 2 ++ 2 files changed, 9 insertions(+) diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c index 3c17c452ae..d1469418e6 100644 --- a/block/dirty-bitmap.c +++ b/block/dirty-bitmap.c @@ -718,3 +718,10 @@ bool bdrv_has_changed_persistent_bitmaps(BlockDriverState *bs) return false; } + +BdrvDirtyBitmap *bdrv_dirty_bitmap_next(BlockDriverState *bs, + BdrvDirtyBitmap *bitmap) +{ + return bitmap == NULL ? QLIST_FIRST(&bs->dirty_bitmaps) : + QLIST_NEXT(bitmap, list); +} diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h index bdf43df694..c8b3110503 100644 --- a/include/block/dirty-bitmap.h +++ b/include/block/dirty-bitmap.h @@ -95,5 +95,7 @@ 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); #endif From 5f72826e7fc62167cf3a37383d1c1151bc9971fe Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 28 Jun 2017 15:05:19 +0300 Subject: [PATCH 41/85] qcow2: add persistent dirty bitmaps support Store persistent dirty bitmaps in qcow2 image. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Max Reitz Message-id: 20170628120530.31251-20-vsementsov@virtuozzo.com [mreitz: Always assign ret in store_bitmap() in case of an error] Signed-off-by: Max Reitz --- block/qcow2-bitmap.c | 476 +++++++++++++++++++++++++++++++++++++++++++ block/qcow2.c | 9 + block/qcow2.h | 1 + 3 files changed, 486 insertions(+) diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c index 52e4616b8c..81c49aecdb 100644 --- a/block/qcow2-bitmap.c +++ b/block/qcow2-bitmap.c @@ -27,6 +27,7 @@ #include "qemu/osdep.h" #include "qapi/error.h" +#include "qemu/cutils.h" #include "block/block_int.h" #include "block/qcow2.h" @@ -42,6 +43,10 @@ #define BME_MIN_GRANULARITY_BITS 9 #define BME_MAX_NAME_SIZE 1023 +#if BME_MAX_TABLE_SIZE * 8ULL > INT_MAX +#error In the code bitmap table physical size assumed to fit into int +#endif + /* Bitmap directory entry flags */ #define BME_RESERVED_FLAGS 0xfffffffcU #define BME_FLAG_IN_USE (1U << 0) @@ -72,6 +77,8 @@ typedef struct Qcow2BitmapTable { uint32_t size; /* number of 64bit entries */ QSIMPLEQ_ENTRY(Qcow2BitmapTable) entry; } Qcow2BitmapTable; +typedef QSIMPLEQ_HEAD(Qcow2BitmapTableList, Qcow2BitmapTable) + Qcow2BitmapTableList; typedef struct Qcow2Bitmap { Qcow2BitmapTable table; @@ -79,6 +86,8 @@ typedef struct Qcow2Bitmap { uint8_t granularity_bits; char *name; + BdrvDirtyBitmap *dirty_bitmap; + QSIMPLEQ_ENTRY(Qcow2Bitmap) entry; } Qcow2Bitmap; typedef QSIMPLEQ_HEAD(Qcow2BitmapList, Qcow2Bitmap) Qcow2BitmapList; @@ -104,6 +113,15 @@ static int update_header_sync(BlockDriverState *bs) return bdrv_flush(bs); } +static inline void bitmap_table_to_be(uint64_t *bitmap_table, size_t size) +{ + size_t i; + + for (i = 0; i < size; ++i) { + cpu_to_be64s(&bitmap_table[i]); + } +} + static int check_table_entry(uint64_t entry, int cluster_size) { uint64_t offset; @@ -127,6 +145,70 @@ static int check_table_entry(uint64_t entry, int cluster_size) return 0; } +static int check_constraints_on_bitmap(BlockDriverState *bs, + const char *name, + uint32_t granularity, + Error **errp) +{ + BDRVQcow2State *s = bs->opaque; + int granularity_bits = ctz32(granularity); + int64_t len = bdrv_getlength(bs); + + assert(granularity > 0); + assert((granularity & (granularity - 1)) == 0); + + if (len < 0) { + error_setg_errno(errp, -len, "Failed to get size of '%s'", + bdrv_get_device_or_node_name(bs)); + return len; + } + + if (granularity_bits > BME_MAX_GRANULARITY_BITS) { + error_setg(errp, "Granularity exceeds maximum (%llu bytes)", + 1ULL << BME_MAX_GRANULARITY_BITS); + return -EINVAL; + } + if (granularity_bits < BME_MIN_GRANULARITY_BITS) { + error_setg(errp, "Granularity is under minimum (%llu bytes)", + 1ULL << BME_MIN_GRANULARITY_BITS); + return -EINVAL; + } + + if ((len > (uint64_t)BME_MAX_PHYS_SIZE << granularity_bits) || + (len > (uint64_t)BME_MAX_TABLE_SIZE * s->cluster_size << + granularity_bits)) + { + error_setg(errp, "Too much space will be occupied by the bitmap. " + "Use larger granularity"); + return -EINVAL; + } + + if (strlen(name) > BME_MAX_NAME_SIZE) { + error_setg(errp, "Name length exceeds maximum (%u characters)", + BME_MAX_NAME_SIZE); + return -EINVAL; + } + + return 0; +} + +static void clear_bitmap_table(BlockDriverState *bs, uint64_t *bitmap_table, + uint32_t bitmap_table_size) +{ + BDRVQcow2State *s = bs->opaque; + int i; + + for (i = 0; i < bitmap_table_size; ++i) { + uint64_t addr = bitmap_table[i] & BME_TABLE_ENTRY_OFFSET_MASK; + if (!addr) { + continue; + } + + qcow2_free_clusters(bs, addr, s->cluster_size, QCOW2_DISCARD_OTHER); + bitmap_table[i] = 0; + } +} + static int bitmap_table_load(BlockDriverState *bs, Qcow2BitmapTable *tb, uint64_t **bitmap_table) { @@ -165,6 +247,28 @@ fail: return ret; } +static int free_bitmap_clusters(BlockDriverState *bs, Qcow2BitmapTable *tb) +{ + int ret; + uint64_t *bitmap_table; + + ret = bitmap_table_load(bs, tb, &bitmap_table); + if (ret < 0) { + assert(bitmap_table == NULL); + return ret; + } + + clear_bitmap_table(bs, bitmap_table, tb->size); + qcow2_free_clusters(bs, tb->offset, tb->size * sizeof(uint64_t), + QCOW2_DISCARD_OTHER); + g_free(bitmap_table); + + tb->offset = 0; + tb->size = 0; + + return 0; +} + /* This function returns the number of disk sectors covered by a single qcow2 * cluster of bitmap data. */ static uint64_t sectors_covered_by_bitmap_cluster(const BDRVQcow2State *s, @@ -748,6 +852,69 @@ static int update_ext_header_and_dir_in_place(BlockDriverState *bs, */ } +static int update_ext_header_and_dir(BlockDriverState *bs, + Qcow2BitmapList *bm_list) +{ + BDRVQcow2State *s = bs->opaque; + int ret; + uint64_t new_offset = 0; + uint64_t new_size = 0; + uint32_t new_nb_bitmaps = 0; + uint64_t old_offset = s->bitmap_directory_offset; + uint64_t old_size = s->bitmap_directory_size; + uint32_t old_nb_bitmaps = s->nb_bitmaps; + uint64_t old_autocl = s->autoclear_features; + + if (bm_list != NULL && !QSIMPLEQ_EMPTY(bm_list)) { + new_nb_bitmaps = bitmap_list_count(bm_list); + + if (new_nb_bitmaps > QCOW2_MAX_BITMAPS) { + return -EINVAL; + } + + ret = bitmap_list_store(bs, bm_list, &new_offset, &new_size, false); + if (ret < 0) { + return ret; + } + + ret = bdrv_flush(bs->file->bs); + if (ret < 0) { + goto fail; + } + + s->autoclear_features |= QCOW2_AUTOCLEAR_BITMAPS; + } else { + s->autoclear_features &= ~(uint64_t)QCOW2_AUTOCLEAR_BITMAPS; + } + + s->bitmap_directory_offset = new_offset; + s->bitmap_directory_size = new_size; + s->nb_bitmaps = new_nb_bitmaps; + + ret = update_header_sync(bs); + if (ret < 0) { + goto fail; + } + + if (old_size > 0) { + qcow2_free_clusters(bs, old_offset, old_size, QCOW2_DISCARD_OTHER); + } + + return 0; + +fail: + if (new_offset > 0) { + qcow2_free_clusters(bs, new_offset, new_size, QCOW2_DISCARD_OTHER); + } + + s->bitmap_directory_offset = old_offset; + s->bitmap_directory_size = old_size; + s->nb_bitmaps = old_nb_bitmaps; + s->autoclear_features = old_autocl; + + return ret; +} + /* for g_slist_foreach for GSList of BdrvDirtyBitmap* elements */ static void release_dirty_bitmap_helper(gpointer bitmap, gpointer bs) @@ -890,3 +1057,312 @@ out: return ret; } + +/* store_bitmap_data() + * Store bitmap to image, filling bitmap table accordingly. + */ +static uint64_t *store_bitmap_data(BlockDriverState *bs, + BdrvDirtyBitmap *bitmap, + uint32_t *bitmap_table_size, Error **errp) +{ + int ret; + BDRVQcow2State *s = bs->opaque; + int64_t sector; + uint64_t sbc; + uint64_t bm_size = bdrv_dirty_bitmap_size(bitmap); + const char *bm_name = bdrv_dirty_bitmap_name(bitmap); + uint8_t *buf = NULL; + BdrvDirtyBitmapIter *dbi; + uint64_t *tb; + uint64_t tb_size = + size_to_clusters(s, + bdrv_dirty_bitmap_serialization_size(bitmap, 0, bm_size)); + + if (tb_size > BME_MAX_TABLE_SIZE || + tb_size * s->cluster_size > BME_MAX_PHYS_SIZE) + { + error_setg(errp, "Bitmap '%s' is too big", bm_name); + return NULL; + } + + tb = g_try_new0(uint64_t, tb_size); + if (tb == NULL) { + error_setg(errp, "No memory"); + return NULL; + } + + dbi = bdrv_dirty_iter_new(bitmap, 0); + buf = g_malloc(s->cluster_size); + sbc = sectors_covered_by_bitmap_cluster(s, bitmap); + assert(DIV_ROUND_UP(bm_size, sbc) == tb_size); + + while ((sector = bdrv_dirty_iter_next(dbi)) != -1) { + uint64_t cluster = sector / sbc; + uint64_t end, write_size; + int64_t off; + + sector = cluster * sbc; + end = MIN(bm_size, sector + sbc); + write_size = + bdrv_dirty_bitmap_serialization_size(bitmap, sector, end - sector); + assert(write_size <= s->cluster_size); + + off = qcow2_alloc_clusters(bs, s->cluster_size); + if (off < 0) { + error_setg_errno(errp, -off, + "Failed to allocate clusters for bitmap '%s'", + bm_name); + goto fail; + } + tb[cluster] = off; + + bdrv_dirty_bitmap_serialize_part(bitmap, buf, sector, end - sector); + if (write_size < s->cluster_size) { + memset(buf + write_size, 0, s->cluster_size - write_size); + } + + ret = qcow2_pre_write_overlap_check(bs, 0, off, s->cluster_size); + if (ret < 0) { + error_setg_errno(errp, -ret, "Qcow2 overlap check failed"); + goto fail; + } + + ret = bdrv_pwrite(bs->file, off, buf, s->cluster_size); + if (ret < 0) { + error_setg_errno(errp, -ret, "Failed to write bitmap '%s' to file", + bm_name); + goto fail; + } + + if (end >= bm_size) { + break; + } + + bdrv_set_dirty_iter(dbi, end); + } + + *bitmap_table_size = tb_size; + g_free(buf); + bdrv_dirty_iter_free(dbi); + + return tb; + +fail: + clear_bitmap_table(bs, tb, tb_size); + g_free(buf); + bdrv_dirty_iter_free(dbi); + g_free(tb); + + return NULL; +} + +/* store_bitmap() + * Store bm->dirty_bitmap to qcow2. + * Set bm->table_offset and bm->table_size accordingly. + */ +static int store_bitmap(BlockDriverState *bs, Qcow2Bitmap *bm, Error **errp) +{ + int ret; + uint64_t *tb; + int64_t tb_offset; + uint32_t tb_size; + BdrvDirtyBitmap *bitmap = bm->dirty_bitmap; + const char *bm_name; + + assert(bitmap != NULL); + + bm_name = bdrv_dirty_bitmap_name(bitmap); + + tb = store_bitmap_data(bs, bitmap, &tb_size, errp); + if (tb == NULL) { + return -EINVAL; + } + + assert(tb_size <= BME_MAX_TABLE_SIZE); + tb_offset = qcow2_alloc_clusters(bs, tb_size * sizeof(tb[0])); + if (tb_offset < 0) { + error_setg_errno(errp, -tb_offset, + "Failed to allocate clusters for bitmap '%s'", + bm_name); + ret = tb_offset; + goto fail; + } + + ret = qcow2_pre_write_overlap_check(bs, 0, tb_offset, + tb_size * sizeof(tb[0])); + if (ret < 0) { + error_setg_errno(errp, -ret, "Qcow2 overlap check failed"); + goto fail; + } + + bitmap_table_to_be(tb, tb_size); + ret = bdrv_pwrite(bs->file, tb_offset, tb, tb_size * sizeof(tb[0])); + if (ret < 0) { + error_setg_errno(errp, -ret, "Failed to write bitmap '%s' to file", + bm_name); + goto fail; + } + + g_free(tb); + + bm->table.offset = tb_offset; + bm->table.size = tb_size; + + return 0; + +fail: + clear_bitmap_table(bs, tb, tb_size); + + if (tb_offset > 0) { + qcow2_free_clusters(bs, tb_offset, tb_size * sizeof(tb[0]), + QCOW2_DISCARD_OTHER); + } + + g_free(tb); + + return ret; +} + +static Qcow2Bitmap *find_bitmap_by_name(Qcow2BitmapList *bm_list, + const char *name) +{ + Qcow2Bitmap *bm; + + QSIMPLEQ_FOREACH(bm, bm_list, entry) { + if (strcmp(name, bm->name) == 0) { + return bm; + } + } + + return NULL; +} + +void qcow2_store_persistent_dirty_bitmaps(BlockDriverState *bs, Error **errp) +{ + BdrvDirtyBitmap *bitmap; + BDRVQcow2State *s = bs->opaque; + uint32_t new_nb_bitmaps = s->nb_bitmaps; + uint64_t new_dir_size = s->bitmap_directory_size; + int ret; + Qcow2BitmapList *bm_list; + Qcow2Bitmap *bm; + Qcow2BitmapTableList drop_tables; + Qcow2BitmapTable *tb, *tb_next; + + if (!bdrv_has_changed_persistent_bitmaps(bs)) { + /* nothing to do */ + return; + } + + if (!can_write(bs)) { + error_setg(errp, "No write access"); + return; + } + + QSIMPLEQ_INIT(&drop_tables); + + if (s->nb_bitmaps == 0) { + bm_list = bitmap_list_new(); + } else { + bm_list = bitmap_list_load(bs, s->bitmap_directory_offset, + s->bitmap_directory_size, errp); + if (bm_list == NULL) { + return; + } + } + + /* check constraints and names */ + for (bitmap = bdrv_dirty_bitmap_next(bs, NULL); bitmap != NULL; + bitmap = bdrv_dirty_bitmap_next(bs, bitmap)) + { + const char *name = bdrv_dirty_bitmap_name(bitmap); + uint32_t granularity = bdrv_dirty_bitmap_granularity(bitmap); + Qcow2Bitmap *bm; + + if (!bdrv_dirty_bitmap_get_persistance(bitmap) || + bdrv_dirty_bitmap_readonly(bitmap)) + { + continue; + } + + if (check_constraints_on_bitmap(bs, name, granularity, errp) < 0) { + error_prepend(errp, "Bitmap '%s' doesn't satisfy the constraints: ", + name); + goto fail; + } + + bm = find_bitmap_by_name(bm_list, name); + if (bm == NULL) { + if (++new_nb_bitmaps > QCOW2_MAX_BITMAPS) { + error_setg(errp, "Too many persistent bitmaps"); + goto fail; + } + + new_dir_size += calc_dir_entry_size(strlen(name), 0); + if (new_dir_size > QCOW2_MAX_BITMAP_DIRECTORY_SIZE) { + error_setg(errp, "Bitmap directory is too large"); + goto fail; + } + + bm = g_new0(Qcow2Bitmap, 1); + bm->name = g_strdup(name); + QSIMPLEQ_INSERT_TAIL(bm_list, bm, entry); + } else { + if (!(bm->flags & BME_FLAG_IN_USE)) { + error_setg(errp, "Bitmap '%s' already exists in the image", + name); + goto fail; + } + tb = g_memdup(&bm->table, sizeof(bm->table)); + bm->table.offset = 0; + bm->table.size = 0; + QSIMPLEQ_INSERT_TAIL(&drop_tables, tb, entry); + } + bm->flags = bdrv_dirty_bitmap_get_autoload(bitmap) ? BME_FLAG_AUTO : 0; + bm->granularity_bits = ctz32(bdrv_dirty_bitmap_granularity(bitmap)); + bm->dirty_bitmap = bitmap; + } + + /* allocate clusters and store bitmaps */ + QSIMPLEQ_FOREACH(bm, bm_list, entry) { + if (bm->dirty_bitmap == NULL) { + continue; + } + + ret = store_bitmap(bs, bm, errp); + if (ret < 0) { + goto fail; + } + } + + ret = update_ext_header_and_dir(bs, bm_list); + if (ret < 0) { + error_setg_errno(errp, -ret, "Failed to update bitmap extension"); + goto fail; + } + + /* Bitmap directory was successfully updated, so, old data can be dropped. + * TODO it is better to reuse these clusters */ + QSIMPLEQ_FOREACH_SAFE(tb, &drop_tables, entry, tb_next) { + free_bitmap_clusters(bs, tb); + g_free(tb); + } + + bitmap_list_free(bm_list); + return; + +fail: + QSIMPLEQ_FOREACH(bm, bm_list, entry) { + if (bm->dirty_bitmap == NULL || bm->table.offset == 0) { + continue; + } + + free_bitmap_clusters(bs, &bm->table); + } + + QSIMPLEQ_FOREACH_SAFE(tb, &drop_tables, entry, tb_next) { + g_free(tb); + } + + bitmap_list_free(bm_list); +} diff --git a/block/qcow2.c b/block/qcow2.c index 19cc49a85b..790b5b188f 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -2046,6 +2046,7 @@ static int qcow2_inactivate(BlockDriverState *bs) { BDRVQcow2State *s = bs->opaque; int ret, result = 0; + Error *local_err = NULL; ret = qcow2_cache_flush(bs, s->l2_table_cache); if (ret) { @@ -2061,6 +2062,14 @@ static int qcow2_inactivate(BlockDriverState *bs) strerror(-ret)); } + qcow2_store_persistent_dirty_bitmaps(bs, &local_err); + if (local_err != NULL) { + result = -EINVAL; + error_report_err(local_err); + error_report("Persistent bitmaps are lost for node '%s'", + bdrv_get_device_or_node_name(bs)); + } + if (result == 0) { qcow2_mark_clean(bs); } diff --git a/block/qcow2.h b/block/qcow2.h index 633bd43841..308cefd0a6 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -647,5 +647,6 @@ int qcow2_check_bitmaps_refcounts(BlockDriverState *bs, BdrvCheckResult *res, 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); #endif From 169b87935966791a860f59a2b17c4e0c7b953779 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 28 Jun 2017 15:05:20 +0300 Subject: [PATCH 42/85] qcow2: store bitmaps on reopening image as read-only Store bitmaps and mark them read-only on reopening image as read-only. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Max Reitz Message-id: 20170628120530.31251-21-vsementsov@virtuozzo.com Signed-off-by: Max Reitz --- block/qcow2-bitmap.c | 22 ++++++++++++++++++++++ block/qcow2.c | 5 +++++ block/qcow2.h | 1 + 3 files changed, 28 insertions(+) diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c index 81c49aecdb..f82478c02a 100644 --- a/block/qcow2-bitmap.c +++ b/block/qcow2-bitmap.c @@ -1366,3 +1366,25 @@ fail: bitmap_list_free(bm_list); } + +int qcow2_reopen_bitmaps_ro(BlockDriverState *bs, Error **errp) +{ + BdrvDirtyBitmap *bitmap; + Error *local_err = NULL; + + qcow2_store_persistent_dirty_bitmaps(bs, &local_err); + if (local_err != NULL) { + error_propagate(errp, local_err); + return -EINVAL; + } + + for (bitmap = bdrv_dirty_bitmap_next(bs, NULL); bitmap != NULL; + bitmap = bdrv_dirty_bitmap_next(bs, bitmap)) + { + if (bdrv_dirty_bitmap_get_persistance(bitmap)) { + bdrv_dirty_bitmap_set_readonly(bitmap, true); + } + } + + return 0; +} diff --git a/block/qcow2.c b/block/qcow2.c index 790b5b188f..1a31f1d360 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -1555,6 +1555,11 @@ static int qcow2_reopen_prepare(BDRVReopenState *state, /* We need to write out any unwritten data if we reopen read-only. */ if ((state->flags & BDRV_O_RDWR) == 0) { + ret = qcow2_reopen_bitmaps_ro(state->bs, errp); + if (ret < 0) { + goto fail; + } + ret = bdrv_flush(state->bs); if (ret < 0) { goto fail; diff --git a/block/qcow2.h b/block/qcow2.h index 308cefd0a6..1f80b5d8d4 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -648,5 +648,6 @@ int qcow2_check_bitmaps_refcounts(BlockDriverState *bs, BdrvCheckResult *res, 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); #endif From 67b792f5edec49fdd4e605d7a1d3a49095cd44bc Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 28 Jun 2017 15:05:21 +0300 Subject: [PATCH 43/85] block: add bdrv_can_store_new_dirty_bitmap This will be needed to check some restrictions before making bitmap persistent in qmp-block-dirty-bitmap-add (this functionality will be added by future patch) Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Max Reitz Reviewed-by: John Snow Message-id: 20170628120530.31251-22-vsementsov@virtuozzo.com Signed-off-by: Max Reitz --- block.c | 22 ++++++++++++++++++++++ include/block/block.h | 3 +++ include/block/block_int.h | 4 ++++ 3 files changed, 29 insertions(+) diff --git a/block.c b/block.c index 700431d5e9..1d441651c9 100644 --- a/block.c +++ b/block.c @@ -4880,3 +4880,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); +} diff --git a/include/block/block.h b/include/block/block.h index 2d637d1da8..f0fdbe8006 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -617,4 +617,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 diff --git a/include/block/block_int.h b/include/block/block_int.h index 254f860972..c9e29bf65e 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -387,6 +387,10 @@ struct BlockDriver { * 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); QLIST_ENTRY(BlockDriver) list; }; From da0eb242ad06b9e33300da7733a582bd61436fd2 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 28 Jun 2017 15:05:22 +0300 Subject: [PATCH 44/85] qcow2: add .bdrv_can_store_new_dirty_bitmap Realize .bdrv_can_store_new_dirty_bitmap interface. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: John Snow Reviewed-by: Max Reitz Message-id: 20170628120530.31251-23-vsementsov@virtuozzo.com Signed-off-by: Max Reitz --- block/qcow2-bitmap.c | 51 ++++++++++++++++++++++++++++++++++++++++++++ block/qcow2.c | 1 + block/qcow2.h | 4 ++++ 3 files changed, 56 insertions(+) diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c index f82478c02a..a8c7e1d190 100644 --- a/block/qcow2-bitmap.c +++ b/block/qcow2-bitmap.c @@ -1388,3 +1388,54 @@ int qcow2_reopen_bitmaps_ro(BlockDriverState *bs, Error **errp) return 0; } + +bool qcow2_can_store_new_dirty_bitmap(BlockDriverState *bs, + const char *name, + uint32_t granularity, + Error **errp) +{ + BDRVQcow2State *s = bs->opaque; + bool found; + Qcow2BitmapList *bm_list; + + if (check_constraints_on_bitmap(bs, name, granularity, errp) != 0) { + goto fail; + } + + if (s->nb_bitmaps == 0) { + return true; + } + + if (s->nb_bitmaps >= QCOW2_MAX_BITMAPS) { + error_setg(errp, + "Maximum number of persistent bitmaps is already reached"); + goto fail; + } + + if (s->bitmap_directory_size + calc_dir_entry_size(strlen(name), 0) > + QCOW2_MAX_BITMAP_DIRECTORY_SIZE) + { + error_setg(errp, "Not enough space in the bitmap directory"); + goto fail; + } + + bm_list = bitmap_list_load(bs, s->bitmap_directory_offset, + s->bitmap_directory_size, errp); + if (bm_list == NULL) { + goto fail; + } + + found = find_bitmap_by_name(bm_list, name); + bitmap_list_free(bm_list); + if (found) { + error_setg(errp, "Bitmap with the same name is already stored"); + goto fail; + } + + return true; + +fail: + error_prepend(errp, "Can't make bitmap '%s' persistent in '%s': ", + name, bdrv_get_device_or_node_name(bs)); + return false; +} diff --git a/block/qcow2.c b/block/qcow2.c index 1a31f1d360..d7046a3a48 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -3989,6 +3989,7 @@ BlockDriver bdrv_qcow2 = { .bdrv_attach_aio_context = qcow2_attach_aio_context, .bdrv_reopen_bitmaps_rw = qcow2_reopen_bitmaps_rw, + .bdrv_can_store_new_dirty_bitmap = qcow2_can_store_new_dirty_bitmap, }; static void bdrv_qcow2_init(void) diff --git a/block/qcow2.h b/block/qcow2.h index 1f80b5d8d4..084a298ebc 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -649,5 +649,9 @@ 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); #endif From fd5ae4ccbea17971e4202bbdaba4501627b15f70 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 28 Jun 2017 15:05:23 +0300 Subject: [PATCH 45/85] qmp: add persistent flag to block-dirty-bitmap-add Add optional 'persistent' flag to qmp command block-dirty-bitmap-add. Default is false. Signed-off-by: Vladimir Sementsov-Ogievskiy Signed-off-by: Denis V. Lunev Reviewed-by: Max Reitz Reviewed-by: John Snow Message-id: 20170628120530.31251-24-vsementsov@virtuozzo.com Signed-off-by: Max Reitz --- blockdev.c | 18 +++++++++++++++++- qapi/block-core.json | 8 +++++++- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/blockdev.c b/blockdev.c index edeb36bd3b..2ef731b1f7 100644 --- a/blockdev.c +++ b/blockdev.c @@ -1983,6 +1983,7 @@ 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, &local_err); if (!local_err) { @@ -2708,9 +2709,11 @@ out: void qmp_block_dirty_bitmap_add(const char *node, const char *name, bool has_granularity, uint32_t granularity, + bool has_persistent, bool persistent, Error **errp) { BlockDriverState *bs; + BdrvDirtyBitmap *bitmap; if (!name || name[0] == '\0') { error_setg(errp, "Bitmap name cannot be empty"); @@ -2733,7 +2736,20 @@ 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 (persistent && + !bdrv_can_store_new_dirty_bitmap(bs, name, granularity, errp)) + { + return; + } + + bitmap = bdrv_create_dirty_bitmap(bs, granularity, name, errp); + if (bitmap != NULL) { + bdrv_dirty_bitmap_set_persistance(bitmap, persistent); + } } void qmp_block_dirty_bitmap_remove(const char *node, const char *name, diff --git a/qapi/block-core.json b/qapi/block-core.json index 957096395a..907ac9d7eb 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -1553,10 +1553,16 @@ # @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) +# # Since: 2.4 ## { 'struct': 'BlockDirtyBitmapAdd', - 'data': { 'node': 'str', 'name': 'str', '*granularity': 'uint32' } } + 'data': { 'node': 'str', 'name': 'str', '*granularity': 'uint32', + '*persistent': 'bool' } } ## # @block-dirty-bitmap-add: From eb738bb50f216db5edbbf0a59c488cd685ef9e61 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 28 Jun 2017 15:05:24 +0300 Subject: [PATCH 46/85] qmp: add autoload parameter to block-dirty-bitmap-add Optional. Default is false. Signed-off-by: Vladimir Sementsov-Ogievskiy Signed-off-by: Denis V. Lunev Reviewed-by: Max Reitz Reviewed-by: John Snow Message-id: 20170628120530.31251-25-vsementsov@virtuozzo.com Signed-off-by: Max Reitz --- blockdev.c | 18 ++++++++++++++++-- qapi/block-core.json | 6 +++++- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/blockdev.c b/blockdev.c index 2ef731b1f7..b7c1449146 100644 --- a/blockdev.c +++ b/blockdev.c @@ -1984,6 +1984,7 @@ static void block_dirty_bitmap_add_prepare(BlkActionState *common, 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) { @@ -2710,6 +2711,7 @@ 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; @@ -2739,6 +2741,15 @@ void qmp_block_dirty_bitmap_add(const char *node, const char *name, 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)) @@ -2747,9 +2758,12 @@ void qmp_block_dirty_bitmap_add(const char *node, const char *name, } bitmap = bdrv_create_dirty_bitmap(bs, granularity, name, errp); - if (bitmap != NULL) { - bdrv_dirty_bitmap_set_persistance(bitmap, persistent); + 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, diff --git a/qapi/block-core.json b/qapi/block-core.json index 907ac9d7eb..fb69efef81 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -1558,11 +1558,15 @@ # 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', - '*persistent': 'bool' } } + '*persistent': 'bool', '*autoload': 'bool' } } ## # @block-dirty-bitmap-add: From a3b52535e8a577d9b12887a34183fe9077ea24d8 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 28 Jun 2017 15:05:25 +0300 Subject: [PATCH 47/85] qmp: add x-debug-block-dirty-bitmap-sha256 Signed-off-by: Vladimir Sementsov-Ogievskiy Message-id: 20170628120530.31251-26-vsementsov@virtuozzo.com Signed-off-by: Max Reitz --- block/dirty-bitmap.c | 5 +++++ blockdev.c | 25 +++++++++++++++++++++++++ include/block/dirty-bitmap.h | 1 + include/qemu/hbitmap.h | 8 ++++++++ qapi/block-core.json | 27 +++++++++++++++++++++++++++ tests/Makefile.include | 2 +- util/hbitmap.c | 11 +++++++++++ 7 files changed, 78 insertions(+), 1 deletion(-) diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c index d1469418e6..5fcf917707 100644 --- a/block/dirty-bitmap.c +++ b/block/dirty-bitmap.c @@ -725,3 +725,8 @@ BdrvDirtyBitmap *bdrv_dirty_bitmap_next(BlockDriverState *bs, 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); +} diff --git a/blockdev.c b/blockdev.c index b7c1449146..988a60d04b 100644 --- a/blockdev.c +++ b/blockdev.c @@ -2820,6 +2820,31 @@ void qmp_block_dirty_bitmap_clear(const char *node, const char *name, 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"); diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h index c8b3110503..8e98aef445 100644 --- a/include/block/dirty-bitmap.h +++ b/include/block/dirty-bitmap.h @@ -97,5 +97,6 @@ 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 diff --git a/include/qemu/hbitmap.h b/include/qemu/hbitmap.h index b52304ac29..d3a74a21fc 100644 --- a/include/qemu/hbitmap.h +++ b/include/qemu/hbitmap.h @@ -252,6 +252,14 @@ void hbitmap_deserialize_ones(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. diff --git a/qapi/block-core.json b/qapi/block-core.json index fb69efef81..9b5047d85d 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -1635,6 +1635,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: # diff --git a/tests/Makefile.include b/tests/Makefile.include index 18cd06a6b3..42e17e21ab 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -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 diff --git a/util/hbitmap.c b/util/hbitmap.c index 0c1591a594..21535cc90b 100644 --- a/util/hbitmap.c +++ b/util/hbitmap.c @@ -13,6 +13,7 @@ #include "qemu/hbitmap.h" #include "qemu/host-utils.h" #include "trace.h" +#include "crypto/hash.h" /* HBitmaps provides an array of bits. The bits are stored as usual in an * array of unsigned longs, but HBitmap is also optimized to provide fast @@ -727,3 +728,13 @@ void hbitmap_free_meta(HBitmap *hb) hbitmap_free(hb->meta); hb->meta = NULL; } + +char *hbitmap_sha256(const HBitmap *bitmap, Error **errp) +{ + size_t size = bitmap->sizes[HBITMAP_LEVELS - 1] * sizeof(unsigned long); + char *data = (char *)bitmap->levels[HBITMAP_LEVELS - 1]; + char *hash = NULL; + qcrypto_hash_digest(QCRYPTO_HASH_ALG_SHA256, data, size, &hash, errp); + + return hash; +} From fc905d3a0cd527e70af5fcce19c43596b7f5c046 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 28 Jun 2017 15:05:26 +0300 Subject: [PATCH 48/85] iotests: test qcow2 persistent dirty bitmap Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Max Reitz Message-id: 20170628120530.31251-27-vsementsov@virtuozzo.com Signed-off-by: Max Reitz --- tests/qemu-iotests/165 | 105 +++++++++++++++++++++++++++++++++++++ tests/qemu-iotests/165.out | 5 ++ tests/qemu-iotests/group | 1 + 3 files changed, 111 insertions(+) create mode 100755 tests/qemu-iotests/165 create mode 100644 tests/qemu-iotests/165.out diff --git a/tests/qemu-iotests/165 b/tests/qemu-iotests/165 new file mode 100755 index 0000000000..74d7b79a0b --- /dev/null +++ b/tests/qemu-iotests/165 @@ -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 . +# + +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']) diff --git a/tests/qemu-iotests/165.out b/tests/qemu-iotests/165.out new file mode 100644 index 0000000000..ae1213e6f8 --- /dev/null +++ b/tests/qemu-iotests/165.out @@ -0,0 +1,5 @@ +. +---------------------------------------------------------------------- +Ran 1 tests + +OK diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group index 613d596356..7d86715aae 100644 --- a/tests/qemu-iotests/group +++ b/tests/qemu-iotests/group @@ -163,6 +163,7 @@ 159 rw auto quick 160 rw auto quick 162 auto quick +165 rw auto quick 170 rw auto quick 171 rw auto quick 172 auto From 56f364e6d745e46c9f6686df9a5d512d32e182ad Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 28 Jun 2017 15:05:27 +0300 Subject: [PATCH 49/85] block/dirty-bitmap: add bdrv_remove_persistent_dirty_bitmap Interface for removing persistent bitmap from its storage. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Max Reitz Reviewed-by: John Snow Message-id: 20170628120530.31251-28-vsementsov@virtuozzo.com Signed-off-by: Max Reitz --- block/dirty-bitmap.c | 18 ++++++++++++++++++ include/block/block_int.h | 3 +++ include/block/dirty-bitmap.h | 3 +++ 3 files changed, 24 insertions(+) diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c index 5fcf917707..b2ca78b4d0 100644 --- a/block/dirty-bitmap.c +++ b/block/dirty-bitmap.c @@ -395,6 +395,7 @@ void bdrv_release_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap) /** * 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) @@ -402,6 +403,23 @@ void bdrv_release_named_dirty_bitmaps(BlockDriverState *bs) bdrv_do_release_matching_dirty_bitmap(bs, NULL, true); } +/** + * 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. */ void bdrv_disable_dirty_bitmap(BdrvDirtyBitmap *bitmap) { diff --git a/include/block/block_int.h b/include/block/block_int.h index c9e29bf65e..58d4ffd533 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -391,6 +391,9 @@ struct BlockDriver { 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; }; diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h index 8e98aef445..93d97f0295 100644 --- a/include/block/dirty-bitmap.h +++ b/include/block/dirty-bitmap.h @@ -25,6 +25,9 @@ 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_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); From 469c71edc729ada7df63063ce2d7586762f4fda7 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 28 Jun 2017 15:05:28 +0300 Subject: [PATCH 50/85] qcow2: add .bdrv_remove_persistent_dirty_bitmap Realize .bdrv_remove_persistent_dirty_bitmap interface. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Max Reitz Reviewed-by: John Snow Message-id: 20170628120530.31251-29-vsementsov@virtuozzo.com Signed-off-by: Max Reitz --- block/qcow2-bitmap.c | 41 +++++++++++++++++++++++++++++++++++++++++ block/qcow2.c | 1 + block/qcow2.h | 3 +++ 3 files changed, 45 insertions(+) diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c index a8c7e1d190..3e8735a20d 100644 --- a/block/qcow2-bitmap.c +++ b/block/qcow2-bitmap.c @@ -1237,6 +1237,47 @@ static Qcow2Bitmap *find_bitmap_by_name(Qcow2BitmapList *bm_list, return NULL; } +void qcow2_remove_persistent_dirty_bitmap(BlockDriverState *bs, + const char *name, + Error **errp) +{ + int ret; + BDRVQcow2State *s = bs->opaque; + Qcow2Bitmap *bm; + Qcow2BitmapList *bm_list; + + if (s->nb_bitmaps == 0) { + /* Absence of the bitmap is not an error: see explanation above + * bdrv_remove_persistent_dirty_bitmap() definition. */ + return; + } + + bm_list = bitmap_list_load(bs, s->bitmap_directory_offset, + s->bitmap_directory_size, errp); + if (bm_list == NULL) { + return; + } + + bm = find_bitmap_by_name(bm_list, name); + if (bm == NULL) { + goto fail; + } + + QSIMPLEQ_REMOVE(bm_list, bm, Qcow2Bitmap, entry); + + ret = update_ext_header_and_dir(bs, bm_list); + if (ret < 0) { + error_setg_errno(errp, -ret, "Failed to update bitmap extension"); + goto fail; + } + + free_bitmap_clusters(bs, &bm->table); + +fail: + bitmap_free(bm); + bitmap_list_free(bm_list); +} + void qcow2_store_persistent_dirty_bitmaps(BlockDriverState *bs, Error **errp) { BdrvDirtyBitmap *bitmap; diff --git a/block/qcow2.c b/block/qcow2.c index d7046a3a48..9d3c70eadb 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -3990,6 +3990,7 @@ BlockDriver bdrv_qcow2 = { .bdrv_reopen_bitmaps_rw = qcow2_reopen_bitmaps_rw, .bdrv_can_store_new_dirty_bitmap = qcow2_can_store_new_dirty_bitmap, + .bdrv_remove_persistent_dirty_bitmap = qcow2_remove_persistent_dirty_bitmap, }; static void bdrv_qcow2_init(void) diff --git a/block/qcow2.h b/block/qcow2.h index 084a298ebc..2df05ac8dd 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -653,5 +653,8 @@ 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 From 5c36c1af274a66e92305d2c33534337552c6bff3 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 28 Jun 2017 15:05:29 +0300 Subject: [PATCH 51/85] qmp: block-dirty-bitmap-remove: remove persistent Remove persistent bitmap from the storage on block-dirty-bitmap-remove. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Max Reitz Reviewed-by: John Snow Message-id: 20170628120530.31251-30-vsementsov@virtuozzo.com Signed-off-by: Max Reitz --- blockdev.c | 10 ++++++++++ qapi/block-core.json | 3 ++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/blockdev.c b/blockdev.c index 988a60d04b..124c23000e 100644 --- a/blockdev.c +++ b/blockdev.c @@ -2771,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) { @@ -2783,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); } diff --git a/qapi/block-core.json b/qapi/block-core.json index 9b5047d85d..4bf11e8b8b 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -1593,7 +1593,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 From 615b5dcf2decbc5f0abb512d13d7e5db2385fa23 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 28 Jun 2017 15:05:30 +0300 Subject: [PATCH 52/85] block: release persistent bitmaps on inactivate We should release them here to reload on invalidate cache. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Max Reitz Message-id: 20170628120530.31251-31-vsementsov@virtuozzo.com Signed-off-by: Max Reitz --- block.c | 4 ++++ block/dirty-bitmap.c | 29 +++++++++++++++++++++++------ include/block/dirty-bitmap.h | 1 + 3 files changed, 28 insertions(+), 6 deletions(-) diff --git a/block.c b/block.c index 1d441651c9..913bb43289 100644 --- a/block.c +++ b/block.c @@ -4082,6 +4082,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; } diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c index b2ca78b4d0..543bddb9b5 100644 --- a/block/dirty-bitmap.c +++ b/block/dirty-bitmap.c @@ -356,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); @@ -389,7 +394,7 @@ 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); } /** @@ -400,7 +405,19 @@ void bdrv_release_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap) */ 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); } /** diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h index 93d97f0295..a79a58d2c3 100644 --- a/include/block/dirty-bitmap.h +++ b/include/block/dirty-bitmap.h @@ -25,6 +25,7 @@ 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); From 2c6f6006429a94fc3f1a2d2e68719f300744566d Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Mon, 26 Jun 2017 13:35:06 +0100 Subject: [PATCH 53/85] iotests: skip 159 & 170 with luks format While the qemu-img dd command does accept --image-opts this is not sufficient to make it work with the LUKS image yet. This is because bdrv_create() still always requires the non-image-opts syntax. Thus we must skip 159/170 with luks for now Reviewed-by: Max Reitz Reviewed-by: Eric Blake Signed-off-by: Daniel P. Berrange Message-id: 20170626123510.20134-2-berrange@redhat.com Signed-off-by: Max Reitz --- tests/qemu-iotests/159 | 1 + tests/qemu-iotests/170 | 1 + 2 files changed, 2 insertions(+) diff --git a/tests/qemu-iotests/159 b/tests/qemu-iotests/159 index 825f05fab8..9b0e1ecc90 100755 --- a/tests/qemu-iotests/159 +++ b/tests/qemu-iotests/159 @@ -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" diff --git a/tests/qemu-iotests/170 b/tests/qemu-iotests/170 index 5b335dbc3e..b79359fc4e 100755 --- a/tests/qemu-iotests/170 +++ b/tests/qemu-iotests/170 @@ -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 ==" From 13a1d4a71bdbc0968886ed656dee0e35dfaaf906 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Mon, 26 Jun 2017 13:35:07 +0100 Subject: [PATCH 54/85] iotests: fix remainining tests to work with LUKS The tests 033, 140, 145 and 157 were all broken when run with LUKS, since they did not correctly use the required image opts args syntax to specify the decryption secret. Further, the 120 test simply does not make sense to run with luks, as the scenario exercised is not relevant. The test 181 was broken when run with LUKS because it didn't take account of fact that $TEST_IMG was already in image opts syntax. The launch_qemu helper also didn't register the secret object providing the LUKS password. Reviewed-by: Max Reitz Reviewed-by: Eric Blake Signed-off-by: Daniel P. Berrange Message-id: 20170626123510.20134-3-berrange@redhat.com Signed-off-by: Max Reitz --- tests/qemu-iotests/033 | 12 ++++++++++-- tests/qemu-iotests/120 | 1 + tests/qemu-iotests/140 | 9 ++++++++- tests/qemu-iotests/145 | 19 +++++++++++++++++-- tests/qemu-iotests/157 | 17 ++++++++++++++--- tests/qemu-iotests/157.out | 16 ++++++++-------- tests/qemu-iotests/174 | 2 +- tests/qemu-iotests/181 | 21 ++++++++++++++++----- tests/qemu-iotests/common.qemu | 9 +++++++-- 9 files changed, 82 insertions(+), 24 deletions(-) diff --git a/tests/qemu-iotests/033 b/tests/qemu-iotests/033 index 16edcf2f00..2cdfd1397a 100755 --- a/tests/qemu-iotests/033 +++ b/tests/qemu-iotests/033 @@ -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 diff --git a/tests/qemu-iotests/120 b/tests/qemu-iotests/120 index 4f88a67fe1..f40b97d099 100755 --- a/tests/qemu-iotests/120 +++ b/tests/qemu-iotests/120 @@ -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 diff --git a/tests/qemu-iotests/140 b/tests/qemu-iotests/140 index 8c80a5a866..f89d0d6789 100755 --- a/tests/qemu-iotests/140 +++ b/tests/qemu-iotests/140 @@ -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 \ diff --git a/tests/qemu-iotests/145 b/tests/qemu-iotests/145 index e6c6bc4a4f..c371b3c46a 100755 --- a/tests/qemu-iotests/145 +++ b/tests/qemu-iotests/145 @@ -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" diff --git a/tests/qemu-iotests/157 b/tests/qemu-iotests/157 index 8d939cb747..2bf02be465 100755 --- a/tests/qemu-iotests/157 +++ b/tests/qemu-iotests/157 @@ -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 diff --git a/tests/qemu-iotests/157.out b/tests/qemu-iotests/157.out index 77a9c03d2c..fdc807f541 100644 --- a/tests/qemu-iotests/157.out +++ b/tests/qemu-iotests/157.out @@ -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 diff --git a/tests/qemu-iotests/174 b/tests/qemu-iotests/174 index c1c20a1a57..552879db32 100755 --- a/tests/qemu-iotests/174 +++ b/tests/qemu-iotests/174 @@ -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 ==" diff --git a/tests/qemu-iotests/181 b/tests/qemu-iotests/181 index f73ad5af2a..0333dda0e3 100755 --- a/tests/qemu-iotests/181 +++ b/tests/qemu-iotests/181 @@ -57,13 +57,24 @@ echo qemu_comm_method="monitor" -_launch_qemu \ - -drive file="${TEST_IMG}",cache=${CACHEMODE},driver=$IMGFMT,id=disk +if [ "$IMGOPTSSYNTAX" = "true" ]; then + _launch_qemu \ + -drive "${TEST_IMG}",cache=${CACHEMODE},id=disk +else + _launch_qemu \ + -drive file="${TEST_IMG}",cache=${CACHEMODE},driver=$IMGFMT,id=disk +fi src=$QEMU_HANDLE -_launch_qemu \ - -drive file="${TEST_IMG}",cache=${CACHEMODE},driver=$IMGFMT,id=disk \ - -incoming "unix:${MIG_SOCKET}" +if [ "$IMGOPTSSYNTAX" = "true" ]; then + _launch_qemu \ + -drive "${TEST_IMG}",cache=${CACHEMODE},id=disk \ + -incoming "unix:${MIG_SOCKET}" +else + _launch_qemu \ + -drive file="${TEST_IMG}",cache=${CACHEMODE},driver=$IMGFMT,id=disk \ + -incoming "unix:${MIG_SOCKET}" +fi dest=$QEMU_HANDLE echo diff --git a/tests/qemu-iotests/common.qemu b/tests/qemu-iotests/common.qemu index 76ef298d3f..7645f1dc72 100644 --- a/tests/qemu-iotests/common.qemu +++ b/tests/qemu-iotests/common.qemu @@ -153,14 +153,19 @@ function _launch_qemu() mkfifo "${fifo_out}" mkfifo "${fifo_in}" + object_options= + if [ -n "$IMGKEYSECRET" ]; then + object_options="--object secret,id=keysec0,data=$IMGKEYSECRET" + fi + if [ -z "$keep_stderr" ]; then QEMU_NEED_PID='y'\ - ${QEMU} -nographic -serial none ${comm} "${@}" >"${fifo_out}" \ + ${QEMU} ${object_options} -nographic -serial none ${comm} "${@}" >"${fifo_out}" \ 2>&1 \ <"${fifo_in}" & elif [ "$keep_stderr" = "y" ]; then QEMU_NEED_PID='y'\ - ${QEMU} -nographic -serial none ${comm} "${@}" >"${fifo_out}" \ + ${QEMU} ${object_options} -nographic -serial none ${comm} "${@}" >"${fifo_out}" \ <"${fifo_in}" & else exit 1 From 307d999198599fe672e69379c99b6db17b961b4e Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Mon, 26 Jun 2017 13:35:08 +0100 Subject: [PATCH 55/85] iotests: reduce PBKDF iterations when testing LUKS By default the PBKDF algorithm used with LUKS is tuned based on the number of iterations to produce 1 second of running time. This makes running the I/O test with the LUKS format orders of magnitude slower than with qcow2/raw formats. When creating LUKS images, set the iteration time to a 10ms to reduce the time overhead for LUKS, since security does not matter in I/O tests. Previously a full 'check -luks' would take $ time ./check -luks Passed all 22 tests real 23m9.988s user 21m46.223s sys 0m22.841s Now it takes $ time ./check -luks Passed all 22 tests real 4m39.235s user 3m29.590s sys 0m24.234s Still slow compared to qcow2/raw, but much improved none the less. Reviewed-by: Max Reitz Reviewed-by: Eric Blake Signed-off-by: Daniel P. Berrange Message-id: 20170626123510.20134-4-berrange@redhat.com Signed-off-by: Max Reitz --- tests/qemu-iotests/149 | 3 + tests/qemu-iotests/149.out | 118 +++++++++++++++---------------- tests/qemu-iotests/common.filter | 3 +- tests/qemu-iotests/common.rc | 3 + 4 files changed, 67 insertions(+), 60 deletions(-) diff --git a/tests/qemu-iotests/149 b/tests/qemu-iotests/149 index 84072513db..f62e618727 100755 --- a/tests/qemu-iotests/149 +++ b/tests/qemu-iotests/149 @@ -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) @@ -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, diff --git a/tests/qemu-iotests/149.out b/tests/qemu-iotests/149.out index 90b5b55efb..b18c4e4678 100644 --- a/tests/qemu-iotests/149.out +++ b/tests/qemu-iotests/149.out @@ -2,7 +2,7 @@ # Create image truncate TEST_DIR/luks-aes-256-xts-plain64-sha1.img --size 4194304MB # Format image -sudo cryptsetup -q -v luksFormat --cipher aes-xts-plain64 --key-size 512 --hash sha1 --key-slot 0 --key-file - TEST_DIR/luks-aes-256-xts-plain64-sha1.img +sudo cryptsetup -q -v luksFormat --cipher aes-xts-plain64 --key-size 512 --hash sha1 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-aes-256-xts-plain64-sha1.img # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha1.img qiotest-145-aes-256-xts-plain64-sha1 # Set dev owner @@ -60,8 +60,8 @@ unlink TEST_DIR/luks-aes-256-xts-plain64-sha1.img # ================= qemu-img aes-256-xts-plain64-sha1 ================= # Create image -qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,cipher-alg=aes-256,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-aes-256-xts-plain64-sha1.img 4194304M -Formatting 'TEST_DIR/luks-aes-256-xts-plain64-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha1 +qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=aes-256,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-aes-256-xts-plain64-sha1.img 4194304M +Formatting 'TEST_DIR/luks-aes-256-xts-plain64-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha1 iter-time=10 # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha1.img qiotest-145-aes-256-xts-plain64-sha1 @@ -122,7 +122,7 @@ unlink TEST_DIR/luks-aes-256-xts-plain64-sha1.img # Create image truncate TEST_DIR/luks-twofish-256-xts-plain64-sha1.img --size 4194304MB # Format image -sudo cryptsetup -q -v luksFormat --cipher twofish-xts-plain64 --key-size 512 --hash sha1 --key-slot 0 --key-file - TEST_DIR/luks-twofish-256-xts-plain64-sha1.img +sudo cryptsetup -q -v luksFormat --cipher twofish-xts-plain64 --key-size 512 --hash sha1 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-twofish-256-xts-plain64-sha1.img # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-twofish-256-xts-plain64-sha1.img qiotest-145-twofish-256-xts-plain64-sha1 # Set dev owner @@ -180,8 +180,8 @@ unlink TEST_DIR/luks-twofish-256-xts-plain64-sha1.img # ================= qemu-img twofish-256-xts-plain64-sha1 ================= # Create image -qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,cipher-alg=twofish-256,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-twofish-256-xts-plain64-sha1.img 4194304M -Formatting 'TEST_DIR/luks-twofish-256-xts-plain64-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=twofish-256 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha1 +qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=twofish-256,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-twofish-256-xts-plain64-sha1.img 4194304M +Formatting 'TEST_DIR/luks-twofish-256-xts-plain64-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=twofish-256 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha1 iter-time=10 # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-twofish-256-xts-plain64-sha1.img qiotest-145-twofish-256-xts-plain64-sha1 @@ -242,7 +242,7 @@ unlink TEST_DIR/luks-twofish-256-xts-plain64-sha1.img # Create image truncate TEST_DIR/luks-serpent-256-xts-plain64-sha1.img --size 4194304MB # Format image -sudo cryptsetup -q -v luksFormat --cipher serpent-xts-plain64 --key-size 512 --hash sha1 --key-slot 0 --key-file - TEST_DIR/luks-serpent-256-xts-plain64-sha1.img +sudo cryptsetup -q -v luksFormat --cipher serpent-xts-plain64 --key-size 512 --hash sha1 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-serpent-256-xts-plain64-sha1.img # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-serpent-256-xts-plain64-sha1.img qiotest-145-serpent-256-xts-plain64-sha1 # Set dev owner @@ -300,8 +300,8 @@ unlink TEST_DIR/luks-serpent-256-xts-plain64-sha1.img # ================= qemu-img serpent-256-xts-plain64-sha1 ================= # Create image -qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,cipher-alg=serpent-256,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-serpent-256-xts-plain64-sha1.img 4194304M -Formatting 'TEST_DIR/luks-serpent-256-xts-plain64-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=serpent-256 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha1 +qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=serpent-256,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-serpent-256-xts-plain64-sha1.img 4194304M +Formatting 'TEST_DIR/luks-serpent-256-xts-plain64-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=serpent-256 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha1 iter-time=10 # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-serpent-256-xts-plain64-sha1.img qiotest-145-serpent-256-xts-plain64-sha1 @@ -362,7 +362,7 @@ unlink TEST_DIR/luks-serpent-256-xts-plain64-sha1.img # Create image truncate TEST_DIR/luks-cast5-128-cbc-plain64-sha1.img --size 4194304MB # Format image -sudo cryptsetup -q -v luksFormat --cipher cast5-cbc-plain64 --key-size 128 --hash sha1 --key-slot 0 --key-file - TEST_DIR/luks-cast5-128-cbc-plain64-sha1.img +sudo cryptsetup -q -v luksFormat --cipher cast5-cbc-plain64 --key-size 128 --hash sha1 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-cast5-128-cbc-plain64-sha1.img # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-cast5-128-cbc-plain64-sha1.img qiotest-145-cast5-128-cbc-plain64-sha1 # Set dev owner @@ -420,8 +420,8 @@ unlink TEST_DIR/luks-cast5-128-cbc-plain64-sha1.img # ================= qemu-img cast5-128-cbc-plain64-sha1 ================= # Create image -qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,cipher-alg=cast5-128,cipher-mode=cbc,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-cast5-128-cbc-plain64-sha1.img 4194304M -Formatting 'TEST_DIR/luks-cast5-128-cbc-plain64-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=cast5-128 cipher-mode=cbc ivgen-alg=plain64 hash-alg=sha1 +qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=cast5-128,cipher-mode=cbc,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-cast5-128-cbc-plain64-sha1.img 4194304M +Formatting 'TEST_DIR/luks-cast5-128-cbc-plain64-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=cast5-128 cipher-mode=cbc ivgen-alg=plain64 hash-alg=sha1 iter-time=10 # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-cast5-128-cbc-plain64-sha1.img qiotest-145-cast5-128-cbc-plain64-sha1 @@ -483,7 +483,7 @@ Skipping cast6-256-xts-plain64-sha1 in blacklist # Create image truncate TEST_DIR/luks-aes-256-cbc-plain-sha1.img --size 4194304MB # Format image -sudo cryptsetup -q -v luksFormat --cipher aes-cbc-plain --key-size 256 --hash sha1 --key-slot 0 --key-file - TEST_DIR/luks-aes-256-cbc-plain-sha1.img +sudo cryptsetup -q -v luksFormat --cipher aes-cbc-plain --key-size 256 --hash sha1 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-aes-256-cbc-plain-sha1.img # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-plain-sha1.img qiotest-145-aes-256-cbc-plain-sha1 # Set dev owner @@ -541,8 +541,8 @@ unlink TEST_DIR/luks-aes-256-cbc-plain-sha1.img # ================= qemu-img aes-256-cbc-plain-sha1 ================= # Create image -qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,cipher-alg=aes-256,cipher-mode=cbc,ivgen-alg=plain,hash-alg=sha1 TEST_DIR/luks-aes-256-cbc-plain-sha1.img 4194304M -Formatting 'TEST_DIR/luks-aes-256-cbc-plain-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=cbc ivgen-alg=plain hash-alg=sha1 +qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=aes-256,cipher-mode=cbc,ivgen-alg=plain,hash-alg=sha1 TEST_DIR/luks-aes-256-cbc-plain-sha1.img 4194304M +Formatting 'TEST_DIR/luks-aes-256-cbc-plain-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=cbc ivgen-alg=plain hash-alg=sha1 iter-time=10 # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-plain-sha1.img qiotest-145-aes-256-cbc-plain-sha1 @@ -603,7 +603,7 @@ unlink TEST_DIR/luks-aes-256-cbc-plain-sha1.img # Create image truncate TEST_DIR/luks-aes-256-cbc-plain64-sha1.img --size 4194304MB # Format image -sudo cryptsetup -q -v luksFormat --cipher aes-cbc-plain64 --key-size 256 --hash sha1 --key-slot 0 --key-file - TEST_DIR/luks-aes-256-cbc-plain64-sha1.img +sudo cryptsetup -q -v luksFormat --cipher aes-cbc-plain64 --key-size 256 --hash sha1 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-aes-256-cbc-plain64-sha1.img # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-plain64-sha1.img qiotest-145-aes-256-cbc-plain64-sha1 # Set dev owner @@ -661,8 +661,8 @@ unlink TEST_DIR/luks-aes-256-cbc-plain64-sha1.img # ================= qemu-img aes-256-cbc-plain64-sha1 ================= # Create image -qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,cipher-alg=aes-256,cipher-mode=cbc,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-aes-256-cbc-plain64-sha1.img 4194304M -Formatting 'TEST_DIR/luks-aes-256-cbc-plain64-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=cbc ivgen-alg=plain64 hash-alg=sha1 +qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=aes-256,cipher-mode=cbc,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-aes-256-cbc-plain64-sha1.img 4194304M +Formatting 'TEST_DIR/luks-aes-256-cbc-plain64-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=cbc ivgen-alg=plain64 hash-alg=sha1 iter-time=10 # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-plain64-sha1.img qiotest-145-aes-256-cbc-plain64-sha1 @@ -723,7 +723,7 @@ unlink TEST_DIR/luks-aes-256-cbc-plain64-sha1.img # Create image truncate TEST_DIR/luks-aes-256-cbc-essiv-sha256-sha1.img --size 4194304MB # Format image -sudo cryptsetup -q -v luksFormat --cipher aes-cbc-essiv:sha256 --key-size 256 --hash sha1 --key-slot 0 --key-file - TEST_DIR/luks-aes-256-cbc-essiv-sha256-sha1.img +sudo cryptsetup -q -v luksFormat --cipher aes-cbc-essiv:sha256 --key-size 256 --hash sha1 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-aes-256-cbc-essiv-sha256-sha1.img # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-essiv-sha256-sha1.img qiotest-145-aes-256-cbc-essiv-sha256-sha1 # Set dev owner @@ -781,8 +781,8 @@ unlink TEST_DIR/luks-aes-256-cbc-essiv-sha256-sha1.img # ================= qemu-img aes-256-cbc-essiv-sha256-sha1 ================= # Create image -qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,cipher-alg=aes-256,cipher-mode=cbc,ivgen-alg=essiv,hash-alg=sha1,ivgen-hash-alg=sha256 TEST_DIR/luks-aes-256-cbc-essiv-sha256-sha1.img 4194304M -Formatting 'TEST_DIR/luks-aes-256-cbc-essiv-sha256-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=cbc ivgen-alg=essiv ivgen-hash-alg=sha256 hash-alg=sha1 +qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=aes-256,cipher-mode=cbc,ivgen-alg=essiv,hash-alg=sha1,ivgen-hash-alg=sha256 TEST_DIR/luks-aes-256-cbc-essiv-sha256-sha1.img 4194304M +Formatting 'TEST_DIR/luks-aes-256-cbc-essiv-sha256-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=cbc ivgen-alg=essiv ivgen-hash-alg=sha256 hash-alg=sha1 iter-time=10 # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-essiv-sha256-sha1.img qiotest-145-aes-256-cbc-essiv-sha256-sha1 @@ -843,7 +843,7 @@ unlink TEST_DIR/luks-aes-256-cbc-essiv-sha256-sha1.img # Create image truncate TEST_DIR/luks-aes-256-xts-essiv-sha256-sha1.img --size 4194304MB # Format image -sudo cryptsetup -q -v luksFormat --cipher aes-xts-essiv:sha256 --key-size 512 --hash sha1 --key-slot 0 --key-file - TEST_DIR/luks-aes-256-xts-essiv-sha256-sha1.img +sudo cryptsetup -q -v luksFormat --cipher aes-xts-essiv:sha256 --key-size 512 --hash sha1 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-aes-256-xts-essiv-sha256-sha1.img # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-essiv-sha256-sha1.img qiotest-145-aes-256-xts-essiv-sha256-sha1 # Set dev owner @@ -901,8 +901,8 @@ unlink TEST_DIR/luks-aes-256-xts-essiv-sha256-sha1.img # ================= qemu-img aes-256-xts-essiv-sha256-sha1 ================= # Create image -qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,cipher-alg=aes-256,cipher-mode=xts,ivgen-alg=essiv,hash-alg=sha1,ivgen-hash-alg=sha256 TEST_DIR/luks-aes-256-xts-essiv-sha256-sha1.img 4194304M -Formatting 'TEST_DIR/luks-aes-256-xts-essiv-sha256-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=xts ivgen-alg=essiv ivgen-hash-alg=sha256 hash-alg=sha1 +qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=aes-256,cipher-mode=xts,ivgen-alg=essiv,hash-alg=sha1,ivgen-hash-alg=sha256 TEST_DIR/luks-aes-256-xts-essiv-sha256-sha1.img 4194304M +Formatting 'TEST_DIR/luks-aes-256-xts-essiv-sha256-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=xts ivgen-alg=essiv ivgen-hash-alg=sha256 hash-alg=sha1 iter-time=10 # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-essiv-sha256-sha1.img qiotest-145-aes-256-xts-essiv-sha256-sha1 @@ -963,7 +963,7 @@ unlink TEST_DIR/luks-aes-256-xts-essiv-sha256-sha1.img # Create image truncate TEST_DIR/luks-aes-128-xts-plain64-sha256-sha1.img --size 4194304MB # Format image -sudo cryptsetup -q -v luksFormat --cipher aes-xts-plain64 --key-size 256 --hash sha1 --key-slot 0 --key-file - TEST_DIR/luks-aes-128-xts-plain64-sha256-sha1.img +sudo cryptsetup -q -v luksFormat --cipher aes-xts-plain64 --key-size 256 --hash sha1 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-aes-128-xts-plain64-sha256-sha1.img # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-128-xts-plain64-sha256-sha1.img qiotest-145-aes-128-xts-plain64-sha256-sha1 # Set dev owner @@ -1021,8 +1021,8 @@ unlink TEST_DIR/luks-aes-128-xts-plain64-sha256-sha1.img # ================= qemu-img aes-128-xts-plain64-sha256-sha1 ================= # Create image -qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,cipher-alg=aes-128,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-aes-128-xts-plain64-sha256-sha1.img 4194304M -Formatting 'TEST_DIR/luks-aes-128-xts-plain64-sha256-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-128 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha1 +qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=aes-128,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-aes-128-xts-plain64-sha256-sha1.img 4194304M +Formatting 'TEST_DIR/luks-aes-128-xts-plain64-sha256-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-128 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha1 iter-time=10 # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-128-xts-plain64-sha256-sha1.img qiotest-145-aes-128-xts-plain64-sha256-sha1 @@ -1083,7 +1083,7 @@ unlink TEST_DIR/luks-aes-128-xts-plain64-sha256-sha1.img # Create image truncate TEST_DIR/luks-aes-192-xts-plain64-sha256-sha1.img --size 4194304MB # Format image -sudo cryptsetup -q -v luksFormat --cipher aes-xts-plain64 --key-size 384 --hash sha1 --key-slot 0 --key-file - TEST_DIR/luks-aes-192-xts-plain64-sha256-sha1.img +sudo cryptsetup -q -v luksFormat --cipher aes-xts-plain64 --key-size 384 --hash sha1 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-aes-192-xts-plain64-sha256-sha1.img # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-192-xts-plain64-sha256-sha1.img qiotest-145-aes-192-xts-plain64-sha256-sha1 # Set dev owner @@ -1141,8 +1141,8 @@ unlink TEST_DIR/luks-aes-192-xts-plain64-sha256-sha1.img # ================= qemu-img aes-192-xts-plain64-sha256-sha1 ================= # Create image -qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,cipher-alg=aes-192,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-aes-192-xts-plain64-sha256-sha1.img 4194304M -Formatting 'TEST_DIR/luks-aes-192-xts-plain64-sha256-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-192 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha1 +qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=aes-192,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-aes-192-xts-plain64-sha256-sha1.img 4194304M +Formatting 'TEST_DIR/luks-aes-192-xts-plain64-sha256-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-192 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha1 iter-time=10 # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-192-xts-plain64-sha256-sha1.img qiotest-145-aes-192-xts-plain64-sha256-sha1 @@ -1203,7 +1203,7 @@ unlink TEST_DIR/luks-aes-192-xts-plain64-sha256-sha1.img # Create image truncate TEST_DIR/luks-twofish-128-xts-plain64-sha1.img --size 4194304MB # Format image -sudo cryptsetup -q -v luksFormat --cipher twofish-xts-plain64 --key-size 256 --hash sha1 --key-slot 0 --key-file - TEST_DIR/luks-twofish-128-xts-plain64-sha1.img +sudo cryptsetup -q -v luksFormat --cipher twofish-xts-plain64 --key-size 256 --hash sha1 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-twofish-128-xts-plain64-sha1.img # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-twofish-128-xts-plain64-sha1.img qiotest-145-twofish-128-xts-plain64-sha1 # Set dev owner @@ -1261,8 +1261,8 @@ unlink TEST_DIR/luks-twofish-128-xts-plain64-sha1.img # ================= qemu-img twofish-128-xts-plain64-sha1 ================= # Create image -qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,cipher-alg=twofish-128,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-twofish-128-xts-plain64-sha1.img 4194304M -Formatting 'TEST_DIR/luks-twofish-128-xts-plain64-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=twofish-128 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha1 +qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=twofish-128,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-twofish-128-xts-plain64-sha1.img 4194304M +Formatting 'TEST_DIR/luks-twofish-128-xts-plain64-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=twofish-128 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha1 iter-time=10 # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-twofish-128-xts-plain64-sha1.img qiotest-145-twofish-128-xts-plain64-sha1 @@ -1324,7 +1324,7 @@ Skipping twofish-192-xts-plain64-sha1 in blacklist # Create image truncate TEST_DIR/luks-serpent-128-xts-plain64-sha1.img --size 4194304MB # Format image -sudo cryptsetup -q -v luksFormat --cipher serpent-xts-plain64 --key-size 256 --hash sha1 --key-slot 0 --key-file - TEST_DIR/luks-serpent-128-xts-plain64-sha1.img +sudo cryptsetup -q -v luksFormat --cipher serpent-xts-plain64 --key-size 256 --hash sha1 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-serpent-128-xts-plain64-sha1.img # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-serpent-128-xts-plain64-sha1.img qiotest-145-serpent-128-xts-plain64-sha1 # Set dev owner @@ -1382,8 +1382,8 @@ unlink TEST_DIR/luks-serpent-128-xts-plain64-sha1.img # ================= qemu-img serpent-128-xts-plain64-sha1 ================= # Create image -qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,cipher-alg=serpent-128,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-serpent-128-xts-plain64-sha1.img 4194304M -Formatting 'TEST_DIR/luks-serpent-128-xts-plain64-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=serpent-128 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha1 +qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=serpent-128,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-serpent-128-xts-plain64-sha1.img 4194304M +Formatting 'TEST_DIR/luks-serpent-128-xts-plain64-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=serpent-128 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha1 iter-time=10 # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-serpent-128-xts-plain64-sha1.img qiotest-145-serpent-128-xts-plain64-sha1 @@ -1444,7 +1444,7 @@ unlink TEST_DIR/luks-serpent-128-xts-plain64-sha1.img # Create image truncate TEST_DIR/luks-serpent-192-xts-plain64-sha1.img --size 4194304MB # Format image -sudo cryptsetup -q -v luksFormat --cipher serpent-xts-plain64 --key-size 384 --hash sha1 --key-slot 0 --key-file - TEST_DIR/luks-serpent-192-xts-plain64-sha1.img +sudo cryptsetup -q -v luksFormat --cipher serpent-xts-plain64 --key-size 384 --hash sha1 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-serpent-192-xts-plain64-sha1.img # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-serpent-192-xts-plain64-sha1.img qiotest-145-serpent-192-xts-plain64-sha1 # Set dev owner @@ -1502,8 +1502,8 @@ unlink TEST_DIR/luks-serpent-192-xts-plain64-sha1.img # ================= qemu-img serpent-192-xts-plain64-sha1 ================= # Create image -qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,cipher-alg=serpent-192,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-serpent-192-xts-plain64-sha1.img 4194304M -Formatting 'TEST_DIR/luks-serpent-192-xts-plain64-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=serpent-192 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha1 +qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=serpent-192,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-serpent-192-xts-plain64-sha1.img 4194304M +Formatting 'TEST_DIR/luks-serpent-192-xts-plain64-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=serpent-192 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha1 iter-time=10 # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-serpent-192-xts-plain64-sha1.img qiotest-145-serpent-192-xts-plain64-sha1 @@ -1566,7 +1566,7 @@ Skipping cast6-192-xts-plain64-sha1 in blacklist # Create image truncate TEST_DIR/luks-aes-256-xts-plain64-sha256.img --size 4194304MB # Format image -sudo cryptsetup -q -v luksFormat --cipher aes-xts-plain64 --key-size 512 --hash sha256 --key-slot 0 --key-file - TEST_DIR/luks-aes-256-xts-plain64-sha256.img +sudo cryptsetup -q -v luksFormat --cipher aes-xts-plain64 --key-size 512 --hash sha256 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-aes-256-xts-plain64-sha256.img # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha256.img qiotest-145-aes-256-xts-plain64-sha256 # Set dev owner @@ -1624,8 +1624,8 @@ unlink TEST_DIR/luks-aes-256-xts-plain64-sha256.img # ================= qemu-img aes-256-xts-plain64-sha256 ================= # Create image -qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,cipher-alg=aes-256,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha256 TEST_DIR/luks-aes-256-xts-plain64-sha256.img 4194304M -Formatting 'TEST_DIR/luks-aes-256-xts-plain64-sha256.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha256 +qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=aes-256,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha256 TEST_DIR/luks-aes-256-xts-plain64-sha256.img 4194304M +Formatting 'TEST_DIR/luks-aes-256-xts-plain64-sha256.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha256 iter-time=10 # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha256.img qiotest-145-aes-256-xts-plain64-sha256 @@ -1688,7 +1688,7 @@ Skipping aes-256-xts-plain64-ripemd160 in blacklist # Create image truncate TEST_DIR/luks-aes-256-xts-plain-sha1-pwslot3.img --size 4194304MB # Format image -sudo cryptsetup -q -v luksFormat --cipher aes-xts-plain --key-size 512 --hash sha1 --key-slot 3 --key-file - TEST_DIR/luks-aes-256-xts-plain-sha1-pwslot3.img +sudo cryptsetup -q -v luksFormat --cipher aes-xts-plain --key-size 512 --hash sha1 --key-slot 3 --key-file - --iter-time 10 TEST_DIR/luks-aes-256-xts-plain-sha1-pwslot3.img # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain-sha1-pwslot3.img qiotest-145-aes-256-xts-plain-sha1-pwslot3 # Set dev owner @@ -1748,21 +1748,21 @@ unlink TEST_DIR/luks-aes-256-xts-plain-sha1-pwslot3.img # Create image truncate TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img --size 4194304MB # Format image -sudo cryptsetup -q -v luksFormat --cipher aes-xts-plain --key-size 512 --hash sha1 --key-slot 0 --key-file - TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img +sudo cryptsetup -q -v luksFormat --cipher aes-xts-plain --key-size 512 --hash sha1 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img # Add password slot 1 -sudo cryptsetup -q -v luksAddKey TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img --key-slot 1 --key-file - TEST_DIR/passwd.txt +sudo cryptsetup -q -v luksAddKey TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img --key-slot 1 --key-file - --iter-time 10 TEST_DIR/passwd.txt # Add password slot 2 -sudo cryptsetup -q -v luksAddKey TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img --key-slot 2 --key-file - TEST_DIR/passwd.txt +sudo cryptsetup -q -v luksAddKey TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img --key-slot 2 --key-file - --iter-time 10 TEST_DIR/passwd.txt # Add password slot 3 -sudo cryptsetup -q -v luksAddKey TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img --key-slot 3 --key-file - TEST_DIR/passwd.txt +sudo cryptsetup -q -v luksAddKey TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img --key-slot 3 --key-file - --iter-time 10 TEST_DIR/passwd.txt # Add password slot 4 -sudo cryptsetup -q -v luksAddKey TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img --key-slot 4 --key-file - TEST_DIR/passwd.txt +sudo cryptsetup -q -v luksAddKey TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img --key-slot 4 --key-file - --iter-time 10 TEST_DIR/passwd.txt # Add password slot 5 -sudo cryptsetup -q -v luksAddKey TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img --key-slot 5 --key-file - TEST_DIR/passwd.txt +sudo cryptsetup -q -v luksAddKey TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img --key-slot 5 --key-file - --iter-time 10 TEST_DIR/passwd.txt # Add password slot 6 -sudo cryptsetup -q -v luksAddKey TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img --key-slot 6 --key-file - TEST_DIR/passwd.txt +sudo cryptsetup -q -v luksAddKey TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img --key-slot 6 --key-file - --iter-time 10 TEST_DIR/passwd.txt # Add password slot 7 -sudo cryptsetup -q -v luksAddKey TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img --key-slot 7 --key-file - TEST_DIR/passwd.txt +sudo cryptsetup -q -v luksAddKey TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img --key-slot 7 --key-file - --iter-time 10 TEST_DIR/passwd.txt # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img qiotest-145-aes-256-xts-plain-sha1-pwallslots # Set dev owner @@ -1820,8 +1820,8 @@ unlink TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img # ================= qemu-img aes-256-xts-plain-sha1-pwallslots ================= # Create image -qemu-img create -f luks --object secret,id=sec0,data=c2xvdDE=,format=base64 -o key-secret=sec0,cipher-alg=aes-256,cipher-mode=xts,ivgen-alg=plain,hash-alg=sha1 TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img 4194304M -Formatting 'TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=xts ivgen-alg=plain hash-alg=sha1 +qemu-img create -f luks --object secret,id=sec0,data=c2xvdDE=,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=aes-256,cipher-mode=xts,ivgen-alg=plain,hash-alg=sha1 TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img 4194304M +Formatting 'TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=xts ivgen-alg=plain hash-alg=sha1 iter-time=10 # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img qiotest-145-aes-256-xts-plain-sha1-pwallslots @@ -1882,7 +1882,7 @@ unlink TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img # Create image truncate TEST_DIR/luks-aes-256-cbc-essiv-auto-sha1.img --size 4194304MB # Format image -sudo cryptsetup -q -v luksFormat --cipher aes-cbc-essiv:sha256 --key-size 256 --hash sha1 --key-slot 0 --key-file - TEST_DIR/luks-aes-256-cbc-essiv-auto-sha1.img +sudo cryptsetup -q -v luksFormat --cipher aes-cbc-essiv:sha256 --key-size 256 --hash sha1 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-aes-256-cbc-essiv-auto-sha1.img # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-essiv-auto-sha1.img qiotest-145-aes-256-cbc-essiv-auto-sha1 # Set dev owner @@ -1940,8 +1940,8 @@ unlink TEST_DIR/luks-aes-256-cbc-essiv-auto-sha1.img # ================= qemu-img aes-256-cbc-essiv-auto-sha1 ================= # Create image -qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,cipher-alg=aes-256,cipher-mode=cbc,ivgen-alg=essiv,hash-alg=sha1 TEST_DIR/luks-aes-256-cbc-essiv-auto-sha1.img 4194304M -Formatting 'TEST_DIR/luks-aes-256-cbc-essiv-auto-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=cbc ivgen-alg=essiv hash-alg=sha1 +qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=aes-256,cipher-mode=cbc,ivgen-alg=essiv,hash-alg=sha1 TEST_DIR/luks-aes-256-cbc-essiv-auto-sha1.img 4194304M +Formatting 'TEST_DIR/luks-aes-256-cbc-essiv-auto-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=cbc ivgen-alg=essiv hash-alg=sha1 iter-time=10 # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-essiv-auto-sha1.img qiotest-145-aes-256-cbc-essiv-auto-sha1 @@ -2002,7 +2002,7 @@ unlink TEST_DIR/luks-aes-256-cbc-essiv-auto-sha1.img # Create image truncate TEST_DIR/luks-aes-256-cbc-plain64-sha256-sha1.img --size 4194304MB # Format image -sudo cryptsetup -q -v luksFormat --cipher aes-cbc-plain64:sha256 --key-size 256 --hash sha1 --key-slot 0 --key-file - TEST_DIR/luks-aes-256-cbc-plain64-sha256-sha1.img +sudo cryptsetup -q -v luksFormat --cipher aes-cbc-plain64:sha256 --key-size 256 --hash sha1 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-aes-256-cbc-plain64-sha256-sha1.img # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-plain64-sha256-sha1.img qiotest-145-aes-256-cbc-plain64-sha256-sha1 # Set dev owner @@ -2060,8 +2060,8 @@ unlink TEST_DIR/luks-aes-256-cbc-plain64-sha256-sha1.img # ================= qemu-img aes-256-cbc-plain64-sha256-sha1 ================= # Create image -qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,cipher-alg=aes-256,cipher-mode=cbc,ivgen-alg=plain64,hash-alg=sha1,ivgen-hash-alg=sha256 TEST_DIR/luks-aes-256-cbc-plain64-sha256-sha1.img 4194304M -Formatting 'TEST_DIR/luks-aes-256-cbc-plain64-sha256-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=cbc ivgen-alg=plain64 ivgen-hash-alg=sha256 hash-alg=sha1 +qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=aes-256,cipher-mode=cbc,ivgen-alg=plain64,hash-alg=sha1,ivgen-hash-alg=sha256 TEST_DIR/luks-aes-256-cbc-plain64-sha256-sha1.img 4194304M +Formatting 'TEST_DIR/luks-aes-256-cbc-plain64-sha256-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=cbc ivgen-alg=plain64 ivgen-hash-alg=sha256 hash-alg=sha1 iter-time=10 # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-plain64-sha256-sha1.img qiotest-145-aes-256-cbc-plain64-sha256-sha1 diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter index 2f595b2ce2..7a58e57317 100644 --- a/tests/qemu-iotests/common.filter +++ b/tests/qemu-iotests/common.filter @@ -126,7 +126,8 @@ _filter_img_create() -e "s# block_state_zero=\\(on\\|off\\)##g" \ -e "s# log_size=[0-9]\\+##g" \ -e "s# refcount_bits=[0-9]\\+##g" \ - -e "s# key-secret=[a-zA-Z0-9]\\+##g" + -e "s# key-secret=[a-zA-Z0-9]\\+##g" \ + -e "s# iter-time=[0-9]\\+##g" } _filter_img_info() diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc index 9fd3130bde..2548e58b99 100644 --- a/tests/qemu-iotests/common.rc +++ b/tests/qemu-iotests/common.rc @@ -107,6 +107,9 @@ _set_default_imgopts() if [ "$IMGFMT" == "qcow2" ] && ! (echo "$IMGOPTS" | grep "compat=" > /dev/null); then IMGOPTS=$(_optstr_add "$IMGOPTS" "compat=1.1") fi + if [ "$IMGFMT" == "luks" ] && ! (echo "$IMGOPTS" | grep "iter-time=" > /dev/null); then + IMGOPTS=$(_optstr_add "$IMGOPTS" "iter-time=10") + fi } _use_sample_img() From a488e71e1e3d1568eb926f80e828e0d440af916b Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Mon, 26 Jun 2017 13:35:09 +0100 Subject: [PATCH 56/85] iotests: add more LUKS hash combination tests Add tests for sha224, sha512, sha384 and ripemd160 hash algorithms. Reviewed-by: Max Reitz Reviewed-by: Eric Blake Signed-off-by: Daniel P. Berrange Message-id: 20170626123510.20134-5-berrange@redhat.com Signed-off-by: Max Reitz --- tests/qemu-iotests/149 | 10 +- tests/qemu-iotests/149.out | 482 ++++++++++++++++++++++++++++++++++++- 2 files changed, 484 insertions(+), 8 deletions(-) diff --git a/tests/qemu-iotests/149 b/tests/qemu-iotests/149 index f62e618727..5faf585461 100755 --- a/tests/qemu-iotests/149 +++ b/tests/qemu-iotests/149 @@ -457,8 +457,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", @@ -504,12 +508,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 = [] diff --git a/tests/qemu-iotests/149.out b/tests/qemu-iotests/149.out index b18c4e4678..2f0454f0b1 100644 --- a/tests/qemu-iotests/149.out +++ b/tests/qemu-iotests/149.out @@ -1562,6 +1562,126 @@ unlink TEST_DIR/luks-serpent-192-xts-plain64-sha1.img Skipping cast6-128-xts-plain64-sha1 in blacklist Skipping cast6-192-xts-plain64-sha1 in blacklist +# ================= dm-crypt aes-256-xts-plain64-sha224 ================= +# Create image +truncate TEST_DIR/luks-aes-256-xts-plain64-sha224.img --size 4194304MB +# Format image +sudo cryptsetup -q -v luksFormat --cipher aes-xts-plain64 --key-size 512 --hash sha224 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-aes-256-xts-plain64-sha224.img +# Open dev +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha224.img qiotest-145-aes-256-xts-plain64-sha224 +# Set dev owner +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha224 +# Write test pattern 0xa7 +qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha224 +wrote 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x13 +qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha224 +wrote 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Close dev +sudo cryptsetup -q -v luksClose qiotest-145-aes-256-xts-plain64-sha224 +# Read test pattern 0xa7 +qemu-io -c read -P 0xa7 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha224.img +read 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Read test pattern 0x13 +qemu-io -c read -P 0x13 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha224.img +read 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x91 +qemu-io -c write -P 0x91 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha224.img +wrote 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x5e +qemu-io -c write -P 0x5e 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha224.img +wrote 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Open dev +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha224.img qiotest-145-aes-256-xts-plain64-sha224 +# Set dev owner +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha224 +# Read test pattern 0x91 +qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha224 +read 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Read test pattern 0x5e +qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha224 +read 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Close dev +sudo cryptsetup -q -v luksClose qiotest-145-aes-256-xts-plain64-sha224 +# Delete image +unlink TEST_DIR/luks-aes-256-xts-plain64-sha224.img + +# ================= qemu-img aes-256-xts-plain64-sha224 ================= +# Create image +qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=aes-256,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha224 TEST_DIR/luks-aes-256-xts-plain64-sha224.img 4194304M +Formatting 'TEST_DIR/luks-aes-256-xts-plain64-sha224.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha224 iter-time=10 + +# Open dev +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha224.img qiotest-145-aes-256-xts-plain64-sha224 +# Set dev owner +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha224 +# Write test pattern 0xa7 +qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha224 +wrote 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x13 +qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha224 +wrote 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Close dev +sudo cryptsetup -q -v luksClose qiotest-145-aes-256-xts-plain64-sha224 +# Read test pattern 0xa7 +qemu-io -c read -P 0xa7 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha224.img +read 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Read test pattern 0x13 +qemu-io -c read -P 0x13 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha224.img +read 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x91 +qemu-io -c write -P 0x91 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha224.img +wrote 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x5e +qemu-io -c write -P 0x5e 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha224.img +wrote 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Open dev +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha224.img qiotest-145-aes-256-xts-plain64-sha224 +# Set dev owner +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha224 +# Read test pattern 0x91 +qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha224 +read 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Read test pattern 0x5e +qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha224 +read 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Close dev +sudo cryptsetup -q -v luksClose qiotest-145-aes-256-xts-plain64-sha224 +# Delete image +unlink TEST_DIR/luks-aes-256-xts-plain64-sha224.img + # ================= dm-crypt aes-256-xts-plain64-sha256 ================= # Create image truncate TEST_DIR/luks-aes-256-xts-plain64-sha256.img --size 4194304MB @@ -1682,8 +1802,366 @@ sudo cryptsetup -q -v luksClose qiotest-145-aes-256-xts-plain64-sha256 # Delete image unlink TEST_DIR/luks-aes-256-xts-plain64-sha256.img -Skipping aes-256-xts-plain64-sha512 in blacklist -Skipping aes-256-xts-plain64-ripemd160 in blacklist +# ================= dm-crypt aes-256-xts-plain64-sha384 ================= +# Create image +truncate TEST_DIR/luks-aes-256-xts-plain64-sha384.img --size 4194304MB +# Format image +sudo cryptsetup -q -v luksFormat --cipher aes-xts-plain64 --key-size 512 --hash sha384 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-aes-256-xts-plain64-sha384.img +# Open dev +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha384.img qiotest-145-aes-256-xts-plain64-sha384 +# Set dev owner +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha384 +# Write test pattern 0xa7 +qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha384 +wrote 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x13 +qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha384 +wrote 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Close dev +sudo cryptsetup -q -v luksClose qiotest-145-aes-256-xts-plain64-sha384 +# Read test pattern 0xa7 +qemu-io -c read -P 0xa7 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha384.img +read 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Read test pattern 0x13 +qemu-io -c read -P 0x13 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha384.img +read 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x91 +qemu-io -c write -P 0x91 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha384.img +wrote 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x5e +qemu-io -c write -P 0x5e 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha384.img +wrote 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Open dev +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha384.img qiotest-145-aes-256-xts-plain64-sha384 +# Set dev owner +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha384 +# Read test pattern 0x91 +qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha384 +read 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Read test pattern 0x5e +qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha384 +read 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Close dev +sudo cryptsetup -q -v luksClose qiotest-145-aes-256-xts-plain64-sha384 +# Delete image +unlink TEST_DIR/luks-aes-256-xts-plain64-sha384.img + +# ================= qemu-img aes-256-xts-plain64-sha384 ================= +# Create image +qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=aes-256,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha384 TEST_DIR/luks-aes-256-xts-plain64-sha384.img 4194304M +Formatting 'TEST_DIR/luks-aes-256-xts-plain64-sha384.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha384 iter-time=10 + +# Open dev +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha384.img qiotest-145-aes-256-xts-plain64-sha384 +# Set dev owner +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha384 +# Write test pattern 0xa7 +qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha384 +wrote 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x13 +qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha384 +wrote 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Close dev +sudo cryptsetup -q -v luksClose qiotest-145-aes-256-xts-plain64-sha384 +# Read test pattern 0xa7 +qemu-io -c read -P 0xa7 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha384.img +read 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Read test pattern 0x13 +qemu-io -c read -P 0x13 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha384.img +read 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x91 +qemu-io -c write -P 0x91 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha384.img +wrote 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x5e +qemu-io -c write -P 0x5e 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha384.img +wrote 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Open dev +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha384.img qiotest-145-aes-256-xts-plain64-sha384 +# Set dev owner +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha384 +# Read test pattern 0x91 +qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha384 +read 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Read test pattern 0x5e +qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha384 +read 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Close dev +sudo cryptsetup -q -v luksClose qiotest-145-aes-256-xts-plain64-sha384 +# Delete image +unlink TEST_DIR/luks-aes-256-xts-plain64-sha384.img + +# ================= dm-crypt aes-256-xts-plain64-sha512 ================= +# Create image +truncate TEST_DIR/luks-aes-256-xts-plain64-sha512.img --size 4194304MB +# Format image +sudo cryptsetup -q -v luksFormat --cipher aes-xts-plain64 --key-size 512 --hash sha512 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-aes-256-xts-plain64-sha512.img +# Open dev +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha512.img qiotest-145-aes-256-xts-plain64-sha512 +# Set dev owner +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha512 +# Write test pattern 0xa7 +qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha512 +wrote 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x13 +qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha512 +wrote 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Close dev +sudo cryptsetup -q -v luksClose qiotest-145-aes-256-xts-plain64-sha512 +# Read test pattern 0xa7 +qemu-io -c read -P 0xa7 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha512.img +read 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Read test pattern 0x13 +qemu-io -c read -P 0x13 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha512.img +read 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x91 +qemu-io -c write -P 0x91 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha512.img +wrote 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x5e +qemu-io -c write -P 0x5e 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha512.img +wrote 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Open dev +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha512.img qiotest-145-aes-256-xts-plain64-sha512 +# Set dev owner +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha512 +# Read test pattern 0x91 +qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha512 +read 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Read test pattern 0x5e +qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha512 +read 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Close dev +sudo cryptsetup -q -v luksClose qiotest-145-aes-256-xts-plain64-sha512 +# Delete image +unlink TEST_DIR/luks-aes-256-xts-plain64-sha512.img + +# ================= qemu-img aes-256-xts-plain64-sha512 ================= +# Create image +qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=aes-256,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha512 TEST_DIR/luks-aes-256-xts-plain64-sha512.img 4194304M +Formatting 'TEST_DIR/luks-aes-256-xts-plain64-sha512.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha512 iter-time=10 + +# Open dev +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha512.img qiotest-145-aes-256-xts-plain64-sha512 +# Set dev owner +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha512 +# Write test pattern 0xa7 +qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha512 +wrote 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x13 +qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha512 +wrote 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Close dev +sudo cryptsetup -q -v luksClose qiotest-145-aes-256-xts-plain64-sha512 +# Read test pattern 0xa7 +qemu-io -c read -P 0xa7 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha512.img +read 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Read test pattern 0x13 +qemu-io -c read -P 0x13 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha512.img +read 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x91 +qemu-io -c write -P 0x91 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha512.img +wrote 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x5e +qemu-io -c write -P 0x5e 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha512.img +wrote 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Open dev +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha512.img qiotest-145-aes-256-xts-plain64-sha512 +# Set dev owner +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha512 +# Read test pattern 0x91 +qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha512 +read 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Read test pattern 0x5e +qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha512 +read 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Close dev +sudo cryptsetup -q -v luksClose qiotest-145-aes-256-xts-plain64-sha512 +# Delete image +unlink TEST_DIR/luks-aes-256-xts-plain64-sha512.img + +# ================= dm-crypt aes-256-xts-plain64-ripemd160 ================= +# Create image +truncate TEST_DIR/luks-aes-256-xts-plain64-ripemd160.img --size 4194304MB +# Format image +sudo cryptsetup -q -v luksFormat --cipher aes-xts-plain64 --key-size 512 --hash ripemd160 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-aes-256-xts-plain64-ripemd160.img +# Open dev +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-ripemd160.img qiotest-145-aes-256-xts-plain64-ripemd160 +# Set dev owner +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-ripemd160 +# Write test pattern 0xa7 +qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-ripemd160 +wrote 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x13 +qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-ripemd160 +wrote 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Close dev +sudo cryptsetup -q -v luksClose qiotest-145-aes-256-xts-plain64-ripemd160 +# Read test pattern 0xa7 +qemu-io -c read -P 0xa7 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-ripemd160.img +read 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Read test pattern 0x13 +qemu-io -c read -P 0x13 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-ripemd160.img +read 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x91 +qemu-io -c write -P 0x91 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-ripemd160.img +wrote 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x5e +qemu-io -c write -P 0x5e 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-ripemd160.img +wrote 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Open dev +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-ripemd160.img qiotest-145-aes-256-xts-plain64-ripemd160 +# Set dev owner +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-ripemd160 +# Read test pattern 0x91 +qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-ripemd160 +read 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Read test pattern 0x5e +qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-ripemd160 +read 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Close dev +sudo cryptsetup -q -v luksClose qiotest-145-aes-256-xts-plain64-ripemd160 +# Delete image +unlink TEST_DIR/luks-aes-256-xts-plain64-ripemd160.img + +# ================= qemu-img aes-256-xts-plain64-ripemd160 ================= +# Create image +qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=aes-256,cipher-mode=xts,ivgen-alg=plain64,hash-alg=ripemd160 TEST_DIR/luks-aes-256-xts-plain64-ripemd160.img 4194304M +Formatting 'TEST_DIR/luks-aes-256-xts-plain64-ripemd160.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=xts ivgen-alg=plain64 hash-alg=ripemd160 iter-time=10 + +# Open dev +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-ripemd160.img qiotest-145-aes-256-xts-plain64-ripemd160 +# Set dev owner +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-ripemd160 +# Write test pattern 0xa7 +qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-ripemd160 +wrote 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x13 +qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-ripemd160 +wrote 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Close dev +sudo cryptsetup -q -v luksClose qiotest-145-aes-256-xts-plain64-ripemd160 +# Read test pattern 0xa7 +qemu-io -c read -P 0xa7 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-ripemd160.img +read 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Read test pattern 0x13 +qemu-io -c read -P 0x13 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-ripemd160.img +read 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x91 +qemu-io -c write -P 0x91 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-ripemd160.img +wrote 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x5e +qemu-io -c write -P 0x5e 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-ripemd160.img +wrote 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Open dev +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-ripemd160.img qiotest-145-aes-256-xts-plain64-ripemd160 +# Set dev owner +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-ripemd160 +# Read test pattern 0x91 +qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-ripemd160 +read 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Read test pattern 0x5e +qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-ripemd160 +read 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Close dev +sudo cryptsetup -q -v luksClose qiotest-145-aes-256-xts-plain64-ripemd160 +# Delete image +unlink TEST_DIR/luks-aes-256-xts-plain64-ripemd160.img + # ================= dm-crypt aes-256-xts-plain-sha1-pwslot3 ================= # Create image truncate TEST_DIR/luks-aes-256-xts-plain-sha1-pwslot3.img --size 4194304MB From ae50b71db01df0bb0b39694ab12354b80c9c95df Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Mon, 26 Jun 2017 13:35:10 +0100 Subject: [PATCH 57/85] iotests: chown LUKS device before qemu-io launches On some distros, whenever you close a block device file descriptor there is a udev rule that resets the file permissions. This can race with the test script when we run qemu-io multiple times against the same block device. Occasionally the second qemu-io invocation will find udev has reset the permissions causing failure. Reviewed-by: Max Reitz Reviewed-by: Eric Blake Signed-off-by: Daniel P. Berrange Message-id: 20170626123510.20134-6-berrange@redhat.com Signed-off-by: Max Reitz --- tests/qemu-iotests/149 | 12 +- tests/qemu-iotests/149.out | 344 ++++++++++++++++++------------------- 2 files changed, 177 insertions(+), 179 deletions(-) diff --git a/tests/qemu-iotests/149 b/tests/qemu-iotests/149 index 5faf585461..223cd68ad5 100755 --- a/tests/qemu-iotests/149 +++ b/tests/qemu-iotests/149 @@ -186,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): @@ -271,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]) @@ -281,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]) @@ -331,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") @@ -365,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") diff --git a/tests/qemu-iotests/149.out b/tests/qemu-iotests/149.out index 2f0454f0b1..5dea00bfa8 100644 --- a/tests/qemu-iotests/149.out +++ b/tests/qemu-iotests/149.out @@ -5,14 +5,14 @@ truncate TEST_DIR/luks-aes-256-xts-plain64-sha1.img --size 4194304MB sudo cryptsetup -q -v luksFormat --cipher aes-xts-plain64 --key-size 512 --hash sha1 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-aes-256-xts-plain64-sha1.img # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha1.img qiotest-145-aes-256-xts-plain64-sha1 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha1 # Write test pattern 0xa7 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha1 qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha1 wrote 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Write test pattern 0x13 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha1 qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha1 wrote 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -41,14 +41,14 @@ wrote 10485760/10485760 bytes at offset 3298534883328 # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha1.img qiotest-145-aes-256-xts-plain64-sha1 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha1 # Read test pattern 0x91 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha1 qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha1 read 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Read test pattern 0x5e +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha1 qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha1 read 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -65,14 +65,14 @@ Formatting 'TEST_DIR/luks-aes-256-xts-plain64-sha1.img', fmt=luks size=439804651 # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha1.img qiotest-145-aes-256-xts-plain64-sha1 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha1 # Write test pattern 0xa7 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha1 qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha1 wrote 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Write test pattern 0x13 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha1 qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha1 wrote 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -101,14 +101,14 @@ wrote 10485760/10485760 bytes at offset 3298534883328 # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha1.img qiotest-145-aes-256-xts-plain64-sha1 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha1 # Read test pattern 0x91 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha1 qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha1 read 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Read test pattern 0x5e +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha1 qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha1 read 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -125,14 +125,14 @@ truncate TEST_DIR/luks-twofish-256-xts-plain64-sha1.img --size 4194304MB sudo cryptsetup -q -v luksFormat --cipher twofish-xts-plain64 --key-size 512 --hash sha1 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-twofish-256-xts-plain64-sha1.img # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-twofish-256-xts-plain64-sha1.img qiotest-145-twofish-256-xts-plain64-sha1 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-twofish-256-xts-plain64-sha1 # Write test pattern 0xa7 +sudo chown UID:GID /dev/mapper/qiotest-145-twofish-256-xts-plain64-sha1 qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-twofish-256-xts-plain64-sha1 wrote 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Write test pattern 0x13 +sudo chown UID:GID /dev/mapper/qiotest-145-twofish-256-xts-plain64-sha1 qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-twofish-256-xts-plain64-sha1 wrote 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -161,14 +161,14 @@ wrote 10485760/10485760 bytes at offset 3298534883328 # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-twofish-256-xts-plain64-sha1.img qiotest-145-twofish-256-xts-plain64-sha1 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-twofish-256-xts-plain64-sha1 # Read test pattern 0x91 +sudo chown UID:GID /dev/mapper/qiotest-145-twofish-256-xts-plain64-sha1 qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-twofish-256-xts-plain64-sha1 read 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Read test pattern 0x5e +sudo chown UID:GID /dev/mapper/qiotest-145-twofish-256-xts-plain64-sha1 qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-twofish-256-xts-plain64-sha1 read 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -185,14 +185,14 @@ Formatting 'TEST_DIR/luks-twofish-256-xts-plain64-sha1.img', fmt=luks size=43980 # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-twofish-256-xts-plain64-sha1.img qiotest-145-twofish-256-xts-plain64-sha1 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-twofish-256-xts-plain64-sha1 # Write test pattern 0xa7 +sudo chown UID:GID /dev/mapper/qiotest-145-twofish-256-xts-plain64-sha1 qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-twofish-256-xts-plain64-sha1 wrote 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Write test pattern 0x13 +sudo chown UID:GID /dev/mapper/qiotest-145-twofish-256-xts-plain64-sha1 qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-twofish-256-xts-plain64-sha1 wrote 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -221,14 +221,14 @@ wrote 10485760/10485760 bytes at offset 3298534883328 # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-twofish-256-xts-plain64-sha1.img qiotest-145-twofish-256-xts-plain64-sha1 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-twofish-256-xts-plain64-sha1 # Read test pattern 0x91 +sudo chown UID:GID /dev/mapper/qiotest-145-twofish-256-xts-plain64-sha1 qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-twofish-256-xts-plain64-sha1 read 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Read test pattern 0x5e +sudo chown UID:GID /dev/mapper/qiotest-145-twofish-256-xts-plain64-sha1 qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-twofish-256-xts-plain64-sha1 read 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -245,14 +245,14 @@ truncate TEST_DIR/luks-serpent-256-xts-plain64-sha1.img --size 4194304MB sudo cryptsetup -q -v luksFormat --cipher serpent-xts-plain64 --key-size 512 --hash sha1 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-serpent-256-xts-plain64-sha1.img # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-serpent-256-xts-plain64-sha1.img qiotest-145-serpent-256-xts-plain64-sha1 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-serpent-256-xts-plain64-sha1 # Write test pattern 0xa7 +sudo chown UID:GID /dev/mapper/qiotest-145-serpent-256-xts-plain64-sha1 qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-256-xts-plain64-sha1 wrote 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Write test pattern 0x13 +sudo chown UID:GID /dev/mapper/qiotest-145-serpent-256-xts-plain64-sha1 qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-256-xts-plain64-sha1 wrote 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -281,14 +281,14 @@ wrote 10485760/10485760 bytes at offset 3298534883328 # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-serpent-256-xts-plain64-sha1.img qiotest-145-serpent-256-xts-plain64-sha1 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-serpent-256-xts-plain64-sha1 # Read test pattern 0x91 +sudo chown UID:GID /dev/mapper/qiotest-145-serpent-256-xts-plain64-sha1 qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-256-xts-plain64-sha1 read 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Read test pattern 0x5e +sudo chown UID:GID /dev/mapper/qiotest-145-serpent-256-xts-plain64-sha1 qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-256-xts-plain64-sha1 read 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -305,14 +305,14 @@ Formatting 'TEST_DIR/luks-serpent-256-xts-plain64-sha1.img', fmt=luks size=43980 # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-serpent-256-xts-plain64-sha1.img qiotest-145-serpent-256-xts-plain64-sha1 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-serpent-256-xts-plain64-sha1 # Write test pattern 0xa7 +sudo chown UID:GID /dev/mapper/qiotest-145-serpent-256-xts-plain64-sha1 qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-256-xts-plain64-sha1 wrote 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Write test pattern 0x13 +sudo chown UID:GID /dev/mapper/qiotest-145-serpent-256-xts-plain64-sha1 qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-256-xts-plain64-sha1 wrote 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -341,14 +341,14 @@ wrote 10485760/10485760 bytes at offset 3298534883328 # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-serpent-256-xts-plain64-sha1.img qiotest-145-serpent-256-xts-plain64-sha1 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-serpent-256-xts-plain64-sha1 # Read test pattern 0x91 +sudo chown UID:GID /dev/mapper/qiotest-145-serpent-256-xts-plain64-sha1 qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-256-xts-plain64-sha1 read 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Read test pattern 0x5e +sudo chown UID:GID /dev/mapper/qiotest-145-serpent-256-xts-plain64-sha1 qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-256-xts-plain64-sha1 read 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -365,14 +365,14 @@ truncate TEST_DIR/luks-cast5-128-cbc-plain64-sha1.img --size 4194304MB sudo cryptsetup -q -v luksFormat --cipher cast5-cbc-plain64 --key-size 128 --hash sha1 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-cast5-128-cbc-plain64-sha1.img # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-cast5-128-cbc-plain64-sha1.img qiotest-145-cast5-128-cbc-plain64-sha1 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-cast5-128-cbc-plain64-sha1 # Write test pattern 0xa7 +sudo chown UID:GID /dev/mapper/qiotest-145-cast5-128-cbc-plain64-sha1 qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-cast5-128-cbc-plain64-sha1 wrote 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Write test pattern 0x13 +sudo chown UID:GID /dev/mapper/qiotest-145-cast5-128-cbc-plain64-sha1 qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-cast5-128-cbc-plain64-sha1 wrote 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -401,14 +401,14 @@ wrote 10485760/10485760 bytes at offset 3298534883328 # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-cast5-128-cbc-plain64-sha1.img qiotest-145-cast5-128-cbc-plain64-sha1 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-cast5-128-cbc-plain64-sha1 # Read test pattern 0x91 +sudo chown UID:GID /dev/mapper/qiotest-145-cast5-128-cbc-plain64-sha1 qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-cast5-128-cbc-plain64-sha1 read 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Read test pattern 0x5e +sudo chown UID:GID /dev/mapper/qiotest-145-cast5-128-cbc-plain64-sha1 qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-cast5-128-cbc-plain64-sha1 read 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -425,14 +425,14 @@ Formatting 'TEST_DIR/luks-cast5-128-cbc-plain64-sha1.img', fmt=luks size=4398046 # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-cast5-128-cbc-plain64-sha1.img qiotest-145-cast5-128-cbc-plain64-sha1 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-cast5-128-cbc-plain64-sha1 # Write test pattern 0xa7 +sudo chown UID:GID /dev/mapper/qiotest-145-cast5-128-cbc-plain64-sha1 qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-cast5-128-cbc-plain64-sha1 wrote 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Write test pattern 0x13 +sudo chown UID:GID /dev/mapper/qiotest-145-cast5-128-cbc-plain64-sha1 qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-cast5-128-cbc-plain64-sha1 wrote 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -461,14 +461,14 @@ wrote 10485760/10485760 bytes at offset 3298534883328 # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-cast5-128-cbc-plain64-sha1.img qiotest-145-cast5-128-cbc-plain64-sha1 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-cast5-128-cbc-plain64-sha1 # Read test pattern 0x91 +sudo chown UID:GID /dev/mapper/qiotest-145-cast5-128-cbc-plain64-sha1 qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-cast5-128-cbc-plain64-sha1 read 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Read test pattern 0x5e +sudo chown UID:GID /dev/mapper/qiotest-145-cast5-128-cbc-plain64-sha1 qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-cast5-128-cbc-plain64-sha1 read 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -486,14 +486,14 @@ truncate TEST_DIR/luks-aes-256-cbc-plain-sha1.img --size 4194304MB sudo cryptsetup -q -v luksFormat --cipher aes-cbc-plain --key-size 256 --hash sha1 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-aes-256-cbc-plain-sha1.img # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-plain-sha1.img qiotest-145-aes-256-cbc-plain-sha1 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain-sha1 # Write test pattern 0xa7 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain-sha1 qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain-sha1 wrote 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Write test pattern 0x13 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain-sha1 qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain-sha1 wrote 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -522,14 +522,14 @@ wrote 10485760/10485760 bytes at offset 3298534883328 # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-plain-sha1.img qiotest-145-aes-256-cbc-plain-sha1 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain-sha1 # Read test pattern 0x91 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain-sha1 qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain-sha1 read 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Read test pattern 0x5e +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain-sha1 qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain-sha1 read 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -546,14 +546,14 @@ Formatting 'TEST_DIR/luks-aes-256-cbc-plain-sha1.img', fmt=luks size=43980465111 # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-plain-sha1.img qiotest-145-aes-256-cbc-plain-sha1 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain-sha1 # Write test pattern 0xa7 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain-sha1 qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain-sha1 wrote 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Write test pattern 0x13 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain-sha1 qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain-sha1 wrote 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -582,14 +582,14 @@ wrote 10485760/10485760 bytes at offset 3298534883328 # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-plain-sha1.img qiotest-145-aes-256-cbc-plain-sha1 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain-sha1 # Read test pattern 0x91 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain-sha1 qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain-sha1 read 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Read test pattern 0x5e +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain-sha1 qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain-sha1 read 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -606,14 +606,14 @@ truncate TEST_DIR/luks-aes-256-cbc-plain64-sha1.img --size 4194304MB sudo cryptsetup -q -v luksFormat --cipher aes-cbc-plain64 --key-size 256 --hash sha1 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-aes-256-cbc-plain64-sha1.img # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-plain64-sha1.img qiotest-145-aes-256-cbc-plain64-sha1 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain64-sha1 # Write test pattern 0xa7 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain64-sha1 qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain64-sha1 wrote 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Write test pattern 0x13 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain64-sha1 qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain64-sha1 wrote 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -642,14 +642,14 @@ wrote 10485760/10485760 bytes at offset 3298534883328 # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-plain64-sha1.img qiotest-145-aes-256-cbc-plain64-sha1 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain64-sha1 # Read test pattern 0x91 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain64-sha1 qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain64-sha1 read 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Read test pattern 0x5e +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain64-sha1 qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain64-sha1 read 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -666,14 +666,14 @@ Formatting 'TEST_DIR/luks-aes-256-cbc-plain64-sha1.img', fmt=luks size=439804651 # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-plain64-sha1.img qiotest-145-aes-256-cbc-plain64-sha1 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain64-sha1 # Write test pattern 0xa7 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain64-sha1 qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain64-sha1 wrote 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Write test pattern 0x13 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain64-sha1 qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain64-sha1 wrote 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -702,14 +702,14 @@ wrote 10485760/10485760 bytes at offset 3298534883328 # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-plain64-sha1.img qiotest-145-aes-256-cbc-plain64-sha1 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain64-sha1 # Read test pattern 0x91 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain64-sha1 qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain64-sha1 read 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Read test pattern 0x5e +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain64-sha1 qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain64-sha1 read 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -726,14 +726,14 @@ truncate TEST_DIR/luks-aes-256-cbc-essiv-sha256-sha1.img --size 4194304MB sudo cryptsetup -q -v luksFormat --cipher aes-cbc-essiv:sha256 --key-size 256 --hash sha1 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-aes-256-cbc-essiv-sha256-sha1.img # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-essiv-sha256-sha1.img qiotest-145-aes-256-cbc-essiv-sha256-sha1 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-essiv-sha256-sha1 # Write test pattern 0xa7 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-essiv-sha256-sha1 qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-essiv-sha256-sha1 wrote 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Write test pattern 0x13 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-essiv-sha256-sha1 qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-essiv-sha256-sha1 wrote 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -762,14 +762,14 @@ wrote 10485760/10485760 bytes at offset 3298534883328 # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-essiv-sha256-sha1.img qiotest-145-aes-256-cbc-essiv-sha256-sha1 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-essiv-sha256-sha1 # Read test pattern 0x91 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-essiv-sha256-sha1 qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-essiv-sha256-sha1 read 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Read test pattern 0x5e +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-essiv-sha256-sha1 qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-essiv-sha256-sha1 read 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -786,14 +786,14 @@ Formatting 'TEST_DIR/luks-aes-256-cbc-essiv-sha256-sha1.img', fmt=luks size=4398 # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-essiv-sha256-sha1.img qiotest-145-aes-256-cbc-essiv-sha256-sha1 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-essiv-sha256-sha1 # Write test pattern 0xa7 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-essiv-sha256-sha1 qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-essiv-sha256-sha1 wrote 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Write test pattern 0x13 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-essiv-sha256-sha1 qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-essiv-sha256-sha1 wrote 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -822,14 +822,14 @@ wrote 10485760/10485760 bytes at offset 3298534883328 # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-essiv-sha256-sha1.img qiotest-145-aes-256-cbc-essiv-sha256-sha1 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-essiv-sha256-sha1 # Read test pattern 0x91 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-essiv-sha256-sha1 qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-essiv-sha256-sha1 read 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Read test pattern 0x5e +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-essiv-sha256-sha1 qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-essiv-sha256-sha1 read 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -846,14 +846,14 @@ truncate TEST_DIR/luks-aes-256-xts-essiv-sha256-sha1.img --size 4194304MB sudo cryptsetup -q -v luksFormat --cipher aes-xts-essiv:sha256 --key-size 512 --hash sha1 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-aes-256-xts-essiv-sha256-sha1.img # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-essiv-sha256-sha1.img qiotest-145-aes-256-xts-essiv-sha256-sha1 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-essiv-sha256-sha1 # Write test pattern 0xa7 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-essiv-sha256-sha1 qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-essiv-sha256-sha1 wrote 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Write test pattern 0x13 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-essiv-sha256-sha1 qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-essiv-sha256-sha1 wrote 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -882,14 +882,14 @@ wrote 10485760/10485760 bytes at offset 3298534883328 # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-essiv-sha256-sha1.img qiotest-145-aes-256-xts-essiv-sha256-sha1 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-essiv-sha256-sha1 # Read test pattern 0x91 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-essiv-sha256-sha1 qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-essiv-sha256-sha1 read 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Read test pattern 0x5e +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-essiv-sha256-sha1 qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-essiv-sha256-sha1 read 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -906,14 +906,14 @@ Formatting 'TEST_DIR/luks-aes-256-xts-essiv-sha256-sha1.img', fmt=luks size=4398 # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-essiv-sha256-sha1.img qiotest-145-aes-256-xts-essiv-sha256-sha1 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-essiv-sha256-sha1 # Write test pattern 0xa7 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-essiv-sha256-sha1 qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-essiv-sha256-sha1 wrote 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Write test pattern 0x13 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-essiv-sha256-sha1 qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-essiv-sha256-sha1 wrote 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -942,14 +942,14 @@ wrote 10485760/10485760 bytes at offset 3298534883328 # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-essiv-sha256-sha1.img qiotest-145-aes-256-xts-essiv-sha256-sha1 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-essiv-sha256-sha1 # Read test pattern 0x91 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-essiv-sha256-sha1 qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-essiv-sha256-sha1 read 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Read test pattern 0x5e +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-essiv-sha256-sha1 qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-essiv-sha256-sha1 read 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -966,14 +966,14 @@ truncate TEST_DIR/luks-aes-128-xts-plain64-sha256-sha1.img --size 4194304MB sudo cryptsetup -q -v luksFormat --cipher aes-xts-plain64 --key-size 256 --hash sha1 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-aes-128-xts-plain64-sha256-sha1.img # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-128-xts-plain64-sha256-sha1.img qiotest-145-aes-128-xts-plain64-sha256-sha1 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-aes-128-xts-plain64-sha256-sha1 # Write test pattern 0xa7 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-128-xts-plain64-sha256-sha1 qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-128-xts-plain64-sha256-sha1 wrote 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Write test pattern 0x13 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-128-xts-plain64-sha256-sha1 qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-128-xts-plain64-sha256-sha1 wrote 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -1002,14 +1002,14 @@ wrote 10485760/10485760 bytes at offset 3298534883328 # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-128-xts-plain64-sha256-sha1.img qiotest-145-aes-128-xts-plain64-sha256-sha1 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-aes-128-xts-plain64-sha256-sha1 # Read test pattern 0x91 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-128-xts-plain64-sha256-sha1 qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-128-xts-plain64-sha256-sha1 read 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Read test pattern 0x5e +sudo chown UID:GID /dev/mapper/qiotest-145-aes-128-xts-plain64-sha256-sha1 qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-128-xts-plain64-sha256-sha1 read 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -1026,14 +1026,14 @@ Formatting 'TEST_DIR/luks-aes-128-xts-plain64-sha256-sha1.img', fmt=luks size=43 # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-128-xts-plain64-sha256-sha1.img qiotest-145-aes-128-xts-plain64-sha256-sha1 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-aes-128-xts-plain64-sha256-sha1 # Write test pattern 0xa7 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-128-xts-plain64-sha256-sha1 qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-128-xts-plain64-sha256-sha1 wrote 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Write test pattern 0x13 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-128-xts-plain64-sha256-sha1 qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-128-xts-plain64-sha256-sha1 wrote 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -1062,14 +1062,14 @@ wrote 10485760/10485760 bytes at offset 3298534883328 # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-128-xts-plain64-sha256-sha1.img qiotest-145-aes-128-xts-plain64-sha256-sha1 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-aes-128-xts-plain64-sha256-sha1 # Read test pattern 0x91 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-128-xts-plain64-sha256-sha1 qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-128-xts-plain64-sha256-sha1 read 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Read test pattern 0x5e +sudo chown UID:GID /dev/mapper/qiotest-145-aes-128-xts-plain64-sha256-sha1 qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-128-xts-plain64-sha256-sha1 read 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -1086,14 +1086,14 @@ truncate TEST_DIR/luks-aes-192-xts-plain64-sha256-sha1.img --size 4194304MB sudo cryptsetup -q -v luksFormat --cipher aes-xts-plain64 --key-size 384 --hash sha1 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-aes-192-xts-plain64-sha256-sha1.img # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-192-xts-plain64-sha256-sha1.img qiotest-145-aes-192-xts-plain64-sha256-sha1 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-aes-192-xts-plain64-sha256-sha1 # Write test pattern 0xa7 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-192-xts-plain64-sha256-sha1 qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-192-xts-plain64-sha256-sha1 wrote 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Write test pattern 0x13 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-192-xts-plain64-sha256-sha1 qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-192-xts-plain64-sha256-sha1 wrote 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -1122,14 +1122,14 @@ wrote 10485760/10485760 bytes at offset 3298534883328 # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-192-xts-plain64-sha256-sha1.img qiotest-145-aes-192-xts-plain64-sha256-sha1 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-aes-192-xts-plain64-sha256-sha1 # Read test pattern 0x91 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-192-xts-plain64-sha256-sha1 qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-192-xts-plain64-sha256-sha1 read 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Read test pattern 0x5e +sudo chown UID:GID /dev/mapper/qiotest-145-aes-192-xts-plain64-sha256-sha1 qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-192-xts-plain64-sha256-sha1 read 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -1146,14 +1146,14 @@ Formatting 'TEST_DIR/luks-aes-192-xts-plain64-sha256-sha1.img', fmt=luks size=43 # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-192-xts-plain64-sha256-sha1.img qiotest-145-aes-192-xts-plain64-sha256-sha1 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-aes-192-xts-plain64-sha256-sha1 # Write test pattern 0xa7 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-192-xts-plain64-sha256-sha1 qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-192-xts-plain64-sha256-sha1 wrote 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Write test pattern 0x13 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-192-xts-plain64-sha256-sha1 qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-192-xts-plain64-sha256-sha1 wrote 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -1182,14 +1182,14 @@ wrote 10485760/10485760 bytes at offset 3298534883328 # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-192-xts-plain64-sha256-sha1.img qiotest-145-aes-192-xts-plain64-sha256-sha1 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-aes-192-xts-plain64-sha256-sha1 # Read test pattern 0x91 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-192-xts-plain64-sha256-sha1 qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-192-xts-plain64-sha256-sha1 read 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Read test pattern 0x5e +sudo chown UID:GID /dev/mapper/qiotest-145-aes-192-xts-plain64-sha256-sha1 qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-192-xts-plain64-sha256-sha1 read 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -1206,14 +1206,14 @@ truncate TEST_DIR/luks-twofish-128-xts-plain64-sha1.img --size 4194304MB sudo cryptsetup -q -v luksFormat --cipher twofish-xts-plain64 --key-size 256 --hash sha1 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-twofish-128-xts-plain64-sha1.img # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-twofish-128-xts-plain64-sha1.img qiotest-145-twofish-128-xts-plain64-sha1 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-twofish-128-xts-plain64-sha1 # Write test pattern 0xa7 +sudo chown UID:GID /dev/mapper/qiotest-145-twofish-128-xts-plain64-sha1 qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-twofish-128-xts-plain64-sha1 wrote 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Write test pattern 0x13 +sudo chown UID:GID /dev/mapper/qiotest-145-twofish-128-xts-plain64-sha1 qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-twofish-128-xts-plain64-sha1 wrote 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -1242,14 +1242,14 @@ wrote 10485760/10485760 bytes at offset 3298534883328 # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-twofish-128-xts-plain64-sha1.img qiotest-145-twofish-128-xts-plain64-sha1 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-twofish-128-xts-plain64-sha1 # Read test pattern 0x91 +sudo chown UID:GID /dev/mapper/qiotest-145-twofish-128-xts-plain64-sha1 qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-twofish-128-xts-plain64-sha1 read 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Read test pattern 0x5e +sudo chown UID:GID /dev/mapper/qiotest-145-twofish-128-xts-plain64-sha1 qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-twofish-128-xts-plain64-sha1 read 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -1266,14 +1266,14 @@ Formatting 'TEST_DIR/luks-twofish-128-xts-plain64-sha1.img', fmt=luks size=43980 # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-twofish-128-xts-plain64-sha1.img qiotest-145-twofish-128-xts-plain64-sha1 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-twofish-128-xts-plain64-sha1 # Write test pattern 0xa7 +sudo chown UID:GID /dev/mapper/qiotest-145-twofish-128-xts-plain64-sha1 qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-twofish-128-xts-plain64-sha1 wrote 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Write test pattern 0x13 +sudo chown UID:GID /dev/mapper/qiotest-145-twofish-128-xts-plain64-sha1 qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-twofish-128-xts-plain64-sha1 wrote 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -1302,14 +1302,14 @@ wrote 10485760/10485760 bytes at offset 3298534883328 # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-twofish-128-xts-plain64-sha1.img qiotest-145-twofish-128-xts-plain64-sha1 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-twofish-128-xts-plain64-sha1 # Read test pattern 0x91 +sudo chown UID:GID /dev/mapper/qiotest-145-twofish-128-xts-plain64-sha1 qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-twofish-128-xts-plain64-sha1 read 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Read test pattern 0x5e +sudo chown UID:GID /dev/mapper/qiotest-145-twofish-128-xts-plain64-sha1 qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-twofish-128-xts-plain64-sha1 read 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -1327,14 +1327,14 @@ truncate TEST_DIR/luks-serpent-128-xts-plain64-sha1.img --size 4194304MB sudo cryptsetup -q -v luksFormat --cipher serpent-xts-plain64 --key-size 256 --hash sha1 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-serpent-128-xts-plain64-sha1.img # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-serpent-128-xts-plain64-sha1.img qiotest-145-serpent-128-xts-plain64-sha1 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-serpent-128-xts-plain64-sha1 # Write test pattern 0xa7 +sudo chown UID:GID /dev/mapper/qiotest-145-serpent-128-xts-plain64-sha1 qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-128-xts-plain64-sha1 wrote 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Write test pattern 0x13 +sudo chown UID:GID /dev/mapper/qiotest-145-serpent-128-xts-plain64-sha1 qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-128-xts-plain64-sha1 wrote 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -1363,14 +1363,14 @@ wrote 10485760/10485760 bytes at offset 3298534883328 # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-serpent-128-xts-plain64-sha1.img qiotest-145-serpent-128-xts-plain64-sha1 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-serpent-128-xts-plain64-sha1 # Read test pattern 0x91 +sudo chown UID:GID /dev/mapper/qiotest-145-serpent-128-xts-plain64-sha1 qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-128-xts-plain64-sha1 read 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Read test pattern 0x5e +sudo chown UID:GID /dev/mapper/qiotest-145-serpent-128-xts-plain64-sha1 qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-128-xts-plain64-sha1 read 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -1387,14 +1387,14 @@ Formatting 'TEST_DIR/luks-serpent-128-xts-plain64-sha1.img', fmt=luks size=43980 # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-serpent-128-xts-plain64-sha1.img qiotest-145-serpent-128-xts-plain64-sha1 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-serpent-128-xts-plain64-sha1 # Write test pattern 0xa7 +sudo chown UID:GID /dev/mapper/qiotest-145-serpent-128-xts-plain64-sha1 qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-128-xts-plain64-sha1 wrote 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Write test pattern 0x13 +sudo chown UID:GID /dev/mapper/qiotest-145-serpent-128-xts-plain64-sha1 qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-128-xts-plain64-sha1 wrote 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -1423,14 +1423,14 @@ wrote 10485760/10485760 bytes at offset 3298534883328 # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-serpent-128-xts-plain64-sha1.img qiotest-145-serpent-128-xts-plain64-sha1 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-serpent-128-xts-plain64-sha1 # Read test pattern 0x91 +sudo chown UID:GID /dev/mapper/qiotest-145-serpent-128-xts-plain64-sha1 qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-128-xts-plain64-sha1 read 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Read test pattern 0x5e +sudo chown UID:GID /dev/mapper/qiotest-145-serpent-128-xts-plain64-sha1 qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-128-xts-plain64-sha1 read 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -1447,14 +1447,14 @@ truncate TEST_DIR/luks-serpent-192-xts-plain64-sha1.img --size 4194304MB sudo cryptsetup -q -v luksFormat --cipher serpent-xts-plain64 --key-size 384 --hash sha1 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-serpent-192-xts-plain64-sha1.img # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-serpent-192-xts-plain64-sha1.img qiotest-145-serpent-192-xts-plain64-sha1 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-serpent-192-xts-plain64-sha1 # Write test pattern 0xa7 +sudo chown UID:GID /dev/mapper/qiotest-145-serpent-192-xts-plain64-sha1 qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-192-xts-plain64-sha1 wrote 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Write test pattern 0x13 +sudo chown UID:GID /dev/mapper/qiotest-145-serpent-192-xts-plain64-sha1 qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-192-xts-plain64-sha1 wrote 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -1483,14 +1483,14 @@ wrote 10485760/10485760 bytes at offset 3298534883328 # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-serpent-192-xts-plain64-sha1.img qiotest-145-serpent-192-xts-plain64-sha1 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-serpent-192-xts-plain64-sha1 # Read test pattern 0x91 +sudo chown UID:GID /dev/mapper/qiotest-145-serpent-192-xts-plain64-sha1 qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-192-xts-plain64-sha1 read 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Read test pattern 0x5e +sudo chown UID:GID /dev/mapper/qiotest-145-serpent-192-xts-plain64-sha1 qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-192-xts-plain64-sha1 read 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -1507,14 +1507,14 @@ Formatting 'TEST_DIR/luks-serpent-192-xts-plain64-sha1.img', fmt=luks size=43980 # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-serpent-192-xts-plain64-sha1.img qiotest-145-serpent-192-xts-plain64-sha1 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-serpent-192-xts-plain64-sha1 # Write test pattern 0xa7 +sudo chown UID:GID /dev/mapper/qiotest-145-serpent-192-xts-plain64-sha1 qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-192-xts-plain64-sha1 wrote 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Write test pattern 0x13 +sudo chown UID:GID /dev/mapper/qiotest-145-serpent-192-xts-plain64-sha1 qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-192-xts-plain64-sha1 wrote 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -1543,14 +1543,14 @@ wrote 10485760/10485760 bytes at offset 3298534883328 # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-serpent-192-xts-plain64-sha1.img qiotest-145-serpent-192-xts-plain64-sha1 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-serpent-192-xts-plain64-sha1 # Read test pattern 0x91 +sudo chown UID:GID /dev/mapper/qiotest-145-serpent-192-xts-plain64-sha1 qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-192-xts-plain64-sha1 read 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Read test pattern 0x5e +sudo chown UID:GID /dev/mapper/qiotest-145-serpent-192-xts-plain64-sha1 qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-192-xts-plain64-sha1 read 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -1569,14 +1569,14 @@ truncate TEST_DIR/luks-aes-256-xts-plain64-sha224.img --size 4194304MB sudo cryptsetup -q -v luksFormat --cipher aes-xts-plain64 --key-size 512 --hash sha224 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-aes-256-xts-plain64-sha224.img # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha224.img qiotest-145-aes-256-xts-plain64-sha224 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha224 # Write test pattern 0xa7 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha224 qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha224 wrote 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Write test pattern 0x13 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha224 qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha224 wrote 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -1605,14 +1605,14 @@ wrote 10485760/10485760 bytes at offset 3298534883328 # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha224.img qiotest-145-aes-256-xts-plain64-sha224 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha224 # Read test pattern 0x91 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha224 qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha224 read 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Read test pattern 0x5e +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha224 qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha224 read 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -1629,14 +1629,14 @@ Formatting 'TEST_DIR/luks-aes-256-xts-plain64-sha224.img', fmt=luks size=4398046 # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha224.img qiotest-145-aes-256-xts-plain64-sha224 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha224 # Write test pattern 0xa7 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha224 qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha224 wrote 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Write test pattern 0x13 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha224 qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha224 wrote 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -1665,14 +1665,14 @@ wrote 10485760/10485760 bytes at offset 3298534883328 # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha224.img qiotest-145-aes-256-xts-plain64-sha224 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha224 # Read test pattern 0x91 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha224 qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha224 read 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Read test pattern 0x5e +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha224 qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha224 read 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -1689,14 +1689,14 @@ truncate TEST_DIR/luks-aes-256-xts-plain64-sha256.img --size 4194304MB sudo cryptsetup -q -v luksFormat --cipher aes-xts-plain64 --key-size 512 --hash sha256 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-aes-256-xts-plain64-sha256.img # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha256.img qiotest-145-aes-256-xts-plain64-sha256 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha256 # Write test pattern 0xa7 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha256 qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha256 wrote 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Write test pattern 0x13 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha256 qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha256 wrote 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -1725,14 +1725,14 @@ wrote 10485760/10485760 bytes at offset 3298534883328 # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha256.img qiotest-145-aes-256-xts-plain64-sha256 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha256 # Read test pattern 0x91 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha256 qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha256 read 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Read test pattern 0x5e +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha256 qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha256 read 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -1749,14 +1749,14 @@ Formatting 'TEST_DIR/luks-aes-256-xts-plain64-sha256.img', fmt=luks size=4398046 # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha256.img qiotest-145-aes-256-xts-plain64-sha256 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha256 # Write test pattern 0xa7 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha256 qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha256 wrote 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Write test pattern 0x13 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha256 qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha256 wrote 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -1785,14 +1785,14 @@ wrote 10485760/10485760 bytes at offset 3298534883328 # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha256.img qiotest-145-aes-256-xts-plain64-sha256 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha256 # Read test pattern 0x91 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha256 qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha256 read 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Read test pattern 0x5e +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha256 qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha256 read 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -1809,14 +1809,14 @@ truncate TEST_DIR/luks-aes-256-xts-plain64-sha384.img --size 4194304MB sudo cryptsetup -q -v luksFormat --cipher aes-xts-plain64 --key-size 512 --hash sha384 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-aes-256-xts-plain64-sha384.img # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha384.img qiotest-145-aes-256-xts-plain64-sha384 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha384 # Write test pattern 0xa7 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha384 qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha384 wrote 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Write test pattern 0x13 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha384 qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha384 wrote 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -1845,14 +1845,14 @@ wrote 10485760/10485760 bytes at offset 3298534883328 # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha384.img qiotest-145-aes-256-xts-plain64-sha384 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha384 # Read test pattern 0x91 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha384 qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha384 read 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Read test pattern 0x5e +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha384 qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha384 read 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -1869,14 +1869,14 @@ Formatting 'TEST_DIR/luks-aes-256-xts-plain64-sha384.img', fmt=luks size=4398046 # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha384.img qiotest-145-aes-256-xts-plain64-sha384 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha384 # Write test pattern 0xa7 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha384 qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha384 wrote 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Write test pattern 0x13 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha384 qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha384 wrote 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -1905,14 +1905,14 @@ wrote 10485760/10485760 bytes at offset 3298534883328 # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha384.img qiotest-145-aes-256-xts-plain64-sha384 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha384 # Read test pattern 0x91 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha384 qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha384 read 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Read test pattern 0x5e +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha384 qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha384 read 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -1929,14 +1929,14 @@ truncate TEST_DIR/luks-aes-256-xts-plain64-sha512.img --size 4194304MB sudo cryptsetup -q -v luksFormat --cipher aes-xts-plain64 --key-size 512 --hash sha512 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-aes-256-xts-plain64-sha512.img # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha512.img qiotest-145-aes-256-xts-plain64-sha512 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha512 # Write test pattern 0xa7 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha512 qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha512 wrote 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Write test pattern 0x13 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha512 qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha512 wrote 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -1965,14 +1965,14 @@ wrote 10485760/10485760 bytes at offset 3298534883328 # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha512.img qiotest-145-aes-256-xts-plain64-sha512 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha512 # Read test pattern 0x91 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha512 qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha512 read 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Read test pattern 0x5e +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha512 qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha512 read 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -1989,14 +1989,14 @@ Formatting 'TEST_DIR/luks-aes-256-xts-plain64-sha512.img', fmt=luks size=4398046 # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha512.img qiotest-145-aes-256-xts-plain64-sha512 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha512 # Write test pattern 0xa7 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha512 qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha512 wrote 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Write test pattern 0x13 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha512 qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha512 wrote 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -2025,14 +2025,14 @@ wrote 10485760/10485760 bytes at offset 3298534883328 # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha512.img qiotest-145-aes-256-xts-plain64-sha512 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha512 # Read test pattern 0x91 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha512 qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha512 read 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Read test pattern 0x5e +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha512 qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha512 read 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -2049,14 +2049,14 @@ truncate TEST_DIR/luks-aes-256-xts-plain64-ripemd160.img --size 4194304MB sudo cryptsetup -q -v luksFormat --cipher aes-xts-plain64 --key-size 512 --hash ripemd160 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-aes-256-xts-plain64-ripemd160.img # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-ripemd160.img qiotest-145-aes-256-xts-plain64-ripemd160 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-ripemd160 # Write test pattern 0xa7 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-ripemd160 qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-ripemd160 wrote 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Write test pattern 0x13 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-ripemd160 qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-ripemd160 wrote 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -2085,14 +2085,14 @@ wrote 10485760/10485760 bytes at offset 3298534883328 # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-ripemd160.img qiotest-145-aes-256-xts-plain64-ripemd160 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-ripemd160 # Read test pattern 0x91 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-ripemd160 qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-ripemd160 read 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Read test pattern 0x5e +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-ripemd160 qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-ripemd160 read 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -2109,14 +2109,14 @@ Formatting 'TEST_DIR/luks-aes-256-xts-plain64-ripemd160.img', fmt=luks size=4398 # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-ripemd160.img qiotest-145-aes-256-xts-plain64-ripemd160 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-ripemd160 # Write test pattern 0xa7 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-ripemd160 qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-ripemd160 wrote 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Write test pattern 0x13 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-ripemd160 qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-ripemd160 wrote 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -2145,14 +2145,14 @@ wrote 10485760/10485760 bytes at offset 3298534883328 # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-ripemd160.img qiotest-145-aes-256-xts-plain64-ripemd160 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-ripemd160 # Read test pattern 0x91 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-ripemd160 qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-ripemd160 read 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Read test pattern 0x5e +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-ripemd160 qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-ripemd160 read 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -2169,14 +2169,14 @@ truncate TEST_DIR/luks-aes-256-xts-plain-sha1-pwslot3.img --size 4194304MB sudo cryptsetup -q -v luksFormat --cipher aes-xts-plain --key-size 512 --hash sha1 --key-slot 3 --key-file - --iter-time 10 TEST_DIR/luks-aes-256-xts-plain-sha1-pwslot3.img # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain-sha1-pwslot3.img qiotest-145-aes-256-xts-plain-sha1-pwslot3 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwslot3 # Write test pattern 0xa7 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwslot3 qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwslot3 wrote 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Write test pattern 0x13 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwslot3 qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwslot3 wrote 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -2205,14 +2205,14 @@ wrote 10485760/10485760 bytes at offset 3298534883328 # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain-sha1-pwslot3.img qiotest-145-aes-256-xts-plain-sha1-pwslot3 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwslot3 # Read test pattern 0x91 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwslot3 qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwslot3 read 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Read test pattern 0x5e +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwslot3 qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwslot3 read 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -2243,14 +2243,14 @@ sudo cryptsetup -q -v luksAddKey TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots sudo cryptsetup -q -v luksAddKey TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img --key-slot 7 --key-file - --iter-time 10 TEST_DIR/passwd.txt # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img qiotest-145-aes-256-xts-plain-sha1-pwallslots -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwallslots # Write test pattern 0xa7 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwallslots qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwallslots wrote 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Write test pattern 0x13 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwallslots qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwallslots wrote 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -2279,14 +2279,14 @@ wrote 10485760/10485760 bytes at offset 3298534883328 # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img qiotest-145-aes-256-xts-plain-sha1-pwallslots -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwallslots # Read test pattern 0x91 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwallslots qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwallslots read 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Read test pattern 0x5e +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwallslots qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwallslots read 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -2303,14 +2303,14 @@ Formatting 'TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img', fmt=luks size= # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img qiotest-145-aes-256-xts-plain-sha1-pwallslots -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwallslots # Write test pattern 0xa7 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwallslots qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwallslots wrote 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Write test pattern 0x13 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwallslots qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwallslots wrote 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -2339,14 +2339,14 @@ wrote 10485760/10485760 bytes at offset 3298534883328 # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img qiotest-145-aes-256-xts-plain-sha1-pwallslots -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwallslots # Read test pattern 0x91 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwallslots qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwallslots read 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Read test pattern 0x5e +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwallslots qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwallslots read 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -2363,14 +2363,14 @@ truncate TEST_DIR/luks-aes-256-cbc-essiv-auto-sha1.img --size 4194304MB sudo cryptsetup -q -v luksFormat --cipher aes-cbc-essiv:sha256 --key-size 256 --hash sha1 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-aes-256-cbc-essiv-auto-sha1.img # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-essiv-auto-sha1.img qiotest-145-aes-256-cbc-essiv-auto-sha1 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-essiv-auto-sha1 # Write test pattern 0xa7 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-essiv-auto-sha1 qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-essiv-auto-sha1 wrote 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Write test pattern 0x13 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-essiv-auto-sha1 qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-essiv-auto-sha1 wrote 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -2399,14 +2399,14 @@ wrote 10485760/10485760 bytes at offset 3298534883328 # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-essiv-auto-sha1.img qiotest-145-aes-256-cbc-essiv-auto-sha1 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-essiv-auto-sha1 # Read test pattern 0x91 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-essiv-auto-sha1 qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-essiv-auto-sha1 read 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Read test pattern 0x5e +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-essiv-auto-sha1 qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-essiv-auto-sha1 read 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -2423,14 +2423,14 @@ Formatting 'TEST_DIR/luks-aes-256-cbc-essiv-auto-sha1.img', fmt=luks size=439804 # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-essiv-auto-sha1.img qiotest-145-aes-256-cbc-essiv-auto-sha1 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-essiv-auto-sha1 # Write test pattern 0xa7 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-essiv-auto-sha1 qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-essiv-auto-sha1 wrote 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Write test pattern 0x13 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-essiv-auto-sha1 qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-essiv-auto-sha1 wrote 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -2459,14 +2459,14 @@ wrote 10485760/10485760 bytes at offset 3298534883328 # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-essiv-auto-sha1.img qiotest-145-aes-256-cbc-essiv-auto-sha1 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-essiv-auto-sha1 # Read test pattern 0x91 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-essiv-auto-sha1 qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-essiv-auto-sha1 read 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Read test pattern 0x5e +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-essiv-auto-sha1 qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-essiv-auto-sha1 read 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -2483,14 +2483,14 @@ truncate TEST_DIR/luks-aes-256-cbc-plain64-sha256-sha1.img --size 4194304MB sudo cryptsetup -q -v luksFormat --cipher aes-cbc-plain64:sha256 --key-size 256 --hash sha1 --key-slot 0 --key-file - --iter-time 10 TEST_DIR/luks-aes-256-cbc-plain64-sha256-sha1.img # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-plain64-sha256-sha1.img qiotest-145-aes-256-cbc-plain64-sha256-sha1 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain64-sha256-sha1 # Write test pattern 0xa7 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain64-sha256-sha1 qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain64-sha256-sha1 wrote 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Write test pattern 0x13 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain64-sha256-sha1 qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain64-sha256-sha1 wrote 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -2519,14 +2519,14 @@ wrote 10485760/10485760 bytes at offset 3298534883328 # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-plain64-sha256-sha1.img qiotest-145-aes-256-cbc-plain64-sha256-sha1 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain64-sha256-sha1 # Read test pattern 0x91 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain64-sha256-sha1 qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain64-sha256-sha1 read 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Read test pattern 0x5e +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain64-sha256-sha1 qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain64-sha256-sha1 read 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -2543,14 +2543,14 @@ Formatting 'TEST_DIR/luks-aes-256-cbc-plain64-sha256-sha1.img', fmt=luks size=43 # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-plain64-sha256-sha1.img qiotest-145-aes-256-cbc-plain64-sha256-sha1 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain64-sha256-sha1 # Write test pattern 0xa7 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain64-sha256-sha1 qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain64-sha256-sha1 wrote 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Write test pattern 0x13 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain64-sha256-sha1 qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain64-sha256-sha1 wrote 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -2579,14 +2579,14 @@ wrote 10485760/10485760 bytes at offset 3298534883328 # Open dev sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-plain64-sha256-sha1.img qiotest-145-aes-256-cbc-plain64-sha256-sha1 -# Set dev owner -sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain64-sha256-sha1 # Read test pattern 0x91 +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain64-sha256-sha1 qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain64-sha256-sha1 read 10485760/10485760 bytes at offset 104857600 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) # Read test pattern 0x5e +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain64-sha256-sha1 qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain64-sha256-sha1 read 10485760/10485760 bytes at offset 3298534883328 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) From 3190683ea322f2c779b85b3f8f59b2f11bdacb2e Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Sun, 2 Jul 2017 17:05:09 +0200 Subject: [PATCH 58/85] iotests: Use absolute paths for executables A user may specify a relative path for accessing qemu, qemu-img, etc. through environment variables ($QEMU_PROG and friends) or a symlink. If a test decides to change its working directory, relative paths will cease to work, however. Work around this by making all of the paths to programs that should undergo testing absolute. Besides "realpath", we also have to use "type -p" to support programs in $PATH. As a side effect, this fixes specifying these programs as symlinks for out-of-tree builds: Before, you would have to create two symlinks, one in the build and one in the source tree (the first one for common.config to find, the second one for the iotest to use). Now it is sufficient to create one in the build tree because common.config will resolve it. Reported-by: Kevin Wolf Signed-off-by: Max Reitz Message-id: 20170702150510.23276-2-mreitz@redhat.com Reviewed-by: Eric Blake Tested-by: Eric Blake Signed-off-by: Max Reitz --- tests/qemu-iotests/common.config | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/qemu-iotests/common.config b/tests/qemu-iotests/common.config index d1b45f5447..e0883a0c65 100644 --- a/tests/qemu-iotests/common.config +++ b/tests/qemu-iotests/common.config @@ -103,6 +103,17 @@ if [ -z "$QEMU_VXHS_PROG" ]; then export QEMU_VXHS_PROG="`set_prog_path qnio_server`" fi +export QEMU_PROG=$(realpath -- "$(type -p "$QEMU_PROG")") +export QEMU_IMG_PROG=$(realpath -- "$(type -p "$QEMU_IMG_PROG")") +export QEMU_IO_PROG=$(realpath -- "$(type -p "$QEMU_IO_PROG")") +export QEMU_NBD_PROG=$(realpath -- "$(type -p "$QEMU_NBD_PROG")") + +# This program is not built as part of qemu but (possibly) provided by the +# system, so it may not be present at all +if [ -n "$QEMU_VXHS_PROG" ]; then + export QEMU_VXHS_PROG=$(realpath -- "$(type -p "$QEMU_VXHS_PROG")") +fi + _qemu_wrapper() { ( From 6f55dfa4a418041033f6457e4635dc3cefe10cf7 Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Sun, 2 Jul 2017 17:05:10 +0200 Subject: [PATCH 59/85] iotests: Add test for colon handling Reviewed-by: Eric Blake Signed-off-by: Max Reitz Message-id: 20170702150510.23276-3-mreitz@redhat.com Signed-off-by: Max Reitz --- tests/qemu-iotests/126 | 105 +++++++++++++++++++++++++++++++++++++ tests/qemu-iotests/126.out | 23 ++++++++ tests/qemu-iotests/group | 1 + 3 files changed, 129 insertions(+) create mode 100755 tests/qemu-iotests/126 create mode 100644 tests/qemu-iotests/126.out diff --git a/tests/qemu-iotests/126 b/tests/qemu-iotests/126 new file mode 100755 index 0000000000..a2d4d6c73d --- /dev/null +++ b/tests/qemu-iotests/126 @@ -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 . +# + +# 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 diff --git a/tests/qemu-iotests/126.out b/tests/qemu-iotests/126.out new file mode 100644 index 0000000000..50d73080fa --- /dev/null +++ b/tests/qemu-iotests/126.out @@ -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 diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group index 7d86715aae..40bef995fe 100644 --- a/tests/qemu-iotests/group +++ b/tests/qemu-iotests/group @@ -130,6 +130,7 @@ 122 rw auto 123 rw auto quick 124 rw auto backing +126 rw auto backing 128 rw auto quick 129 rw auto quick 130 rw auto quick From b43671f80cda8d0f11dcb929ed76fbd680c29cec Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Mon, 3 Jul 2017 13:09:50 -0500 Subject: [PATCH 60/85] tests: Avoid non-portable 'echo -ARG' POSIX says that backslashes in the arguments to 'echo', as well as any use of 'echo -n' and 'echo -e', are non-portable; it recommends people should favor 'printf' instead. This is definitely true where we do not control which shell is running (such as in makefile snippets or in documentation examples). But even for scripts where we require bash (and therefore, where echo does what we want by default), it is still possible to use 'shopt -s xpg_echo' to change bash's behavior of echo. And setting a good example never hurts when we are not sure if a snippet will be copied from a bash-only script to a general shell script (although I don't change the use of non-portable \e for ESC when we know the running shell is bash). Replace 'echo -n "..."' with 'printf %s "..."', and 'echo -e "..."' with 'printf %b "...\n"', with the optimization that the %s/%b argument can be omitted if the string being printed is a strict literal with no '%', '$', or '`' (we could technically also make this optimization when there are $ or `` substitutions but where we can prove their results will not be problematic, but proving that such substitutions are safe makes the patch less trivial compared to just being consistent). In the qemu-iotests check script, fix unusual shell quoting that would result in word-splitting if 'date' outputs a space. In test 051, take an opportunity to shorten the line. In test 068, get rid of a pointless second invocation of bash. CC: qemu-trivial@nongnu.org Signed-off-by: Eric Blake Message-id: 20170703180950.9895-1-eblake@redhat.com Signed-off-by: Max Reitz --- qemu-options.hx | 4 ++-- tests/multiboot/run_test.sh | 10 ++++---- tests/qemu-iotests/051 | 7 +++--- tests/qemu-iotests/068 | 2 +- tests/qemu-iotests/142 | 48 ++++++++++++++++++------------------- tests/qemu-iotests/171 | 14 +++++------ tests/qemu-iotests/check | 18 +++++++------- tests/rocker/all | 10 ++++---- tests/tcg/cris/Makefile | 8 +++---- 9 files changed, 61 insertions(+), 60 deletions(-) diff --git a/qemu-options.hx b/qemu-options.hx index 76b1c67737..2cc70b9cfc 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -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 diff --git a/tests/multiboot/run_test.sh b/tests/multiboot/run_test.sh index 78d7edfc3b..c8f3da8f37 100755 --- a/tests/multiboot/run_test.sh +++ b/tests/multiboot/run_test.sh @@ -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 diff --git a/tests/qemu-iotests/051 b/tests/qemu-iotests/051 index 26c29deb51..c8cfc764bc 100755 --- a/tests/qemu-iotests/051 +++ b/tests/qemu-iotests/051 @@ -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 diff --git a/tests/qemu-iotests/068 b/tests/qemu-iotests/068 index 3801b65b9d..cfa0f2aed5 100755 --- a/tests/qemu-iotests/068 +++ b/tests/qemu-iotests/068 @@ -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 diff --git a/tests/qemu-iotests/142 b/tests/qemu-iotests/142 index 9a5b713256..1639c83985 100755 --- a/tests/qemu-iotests/142 +++ b/tests/qemu-iotests/142 @@ -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" } diff --git a/tests/qemu-iotests/171 b/tests/qemu-iotests/171 index 257be10a0e..bcfaaf1be2 100755 --- a/tests/qemu-iotests/171 +++ b/tests/qemu-iotests/171 @@ -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() { diff --git a/tests/qemu-iotests/check b/tests/qemu-iotests/check index 4b1c6749b7..9ded37c128 100755 --- a/tests/qemu-iotests/check +++ b/tests/qemu-iotests/check @@ -141,7 +141,7 @@ _wallclock() _timestamp() { now=`date "+%T"` - echo -n " [$now]" + printf %s " [$now]" } _wrapup() @@ -255,7 +255,7 @@ seq="check" for seq in $list do err=false - echo -n "$seq" + printf %s "$seq" if [ -n "$TESTS_REMAINING_LOG" ] ; then sed -e "s/$seq//" -e 's/ / /' -e 's/^ *//' $TESTS_REMAINING_LOG > $TESTS_REMAINING_LOG.tmp mv $TESTS_REMAINING_LOG.tmp $TESTS_REMAINING_LOG @@ -281,9 +281,9 @@ do rm -f $seq.out.bad lasttime=`sed -n -e "/^$seq /s/.* //p" <$TIMESTAMP_FILE` if [ "X$lasttime" != X ]; then - echo -n " ${lasttime}s ..." + printf %s " ${lasttime}s ..." else - echo -n " " # prettier output with timestamps. + printf " " # prettier output with timestamps. fi rm -f core $seq.notrun @@ -291,7 +291,7 @@ do echo "$seq" > "${TEST_DIR}"/check.sts start=`_wallclock` - $timestamp && echo -n " ["`date "+%T"`"]" + $timestamp && printf %s " [$(date "+%T")]" if [ "$(head -n 1 "$source_iotests/$seq")" == "#!/usr/bin/env python" ]; then run_command="$PYTHON $seq" @@ -314,21 +314,21 @@ do if [ -f core ] then - echo -n " [dumped core]" + printf " [dumped core]" mv core $seq.core err=true fi if [ -f $seq.notrun ] then - $timestamp || echo -n " [not run] " - $timestamp && echo " [not run]" && echo -n " $seq -- " + $timestamp || printf " [not run] " + $timestamp && echo " [not run]" && printf %s " $seq -- " cat $seq.notrun notrun="$notrun $seq" else if [ $sts -ne 0 ] then - echo -n " [failed, exit status $sts]" + printf %s " [failed, exit status $sts]" err=true fi diff --git a/tests/rocker/all b/tests/rocker/all index d5ae9632a2..3f9b786daf 100755 --- a/tests/rocker/all +++ b/tests/rocker/all @@ -1,19 +1,19 @@ -echo -n "Running port test... " +printf "Running port test... " ./port if [ $? -eq 0 ]; then echo "pass"; else echo "FAILED"; exit 1; fi -echo -n "Running bridge test... " +printf "Running bridge test... " ./bridge if [ $? -eq 0 ]; then echo "pass"; else echo "FAILED"; exit 1; fi -echo -n "Running bridge STP test... " +printf "Running bridge STP test... " ./bridge-stp if [ $? -eq 0 ]; then echo "pass"; else echo "FAILED"; exit 1; fi -echo -n "Running bridge VLAN test... " +printf "Running bridge VLAN test... " ./bridge-vlan if [ $? -eq 0 ]; then echo "pass"; else echo "FAILED"; exit 1; fi -echo -n "Running bridge VLAN STP test... " +printf "Running bridge VLAN STP test... " ./bridge-vlan-stp if [ $? -eq 0 ]; then echo "pass"; else echo "FAILED"; exit 1; fi diff --git a/tests/tcg/cris/Makefile b/tests/tcg/cris/Makefile index 6b3dba446c..664b30ce81 100644 --- a/tests/tcg/cris/Makefile +++ b/tests/tcg/cris/Makefile @@ -150,17 +150,17 @@ check_addcv17.tst: crtv10.o sysv10.o build: $(CRT) $(SYS) $(TESTCASES) check: $(CRT) $(SYS) $(TESTCASES) - @echo -e "\nQEMU simulator." + @printf "\nQEMU simulator.\n" for case in $(TESTCASES); do \ - echo -n "$$case "; \ + printf %s "$$case "; \ SIMARGS=; \ case $$case in *v17*) SIMARGS="-cpu crisv17";; esac; \ $(SIM) $$SIMARGS ./$$case; \ done check-g: $(CRT) $(SYS) $(TESTCASES) - @echo -e "\nGDB simulator." + @printf "\nGDB simulator.\n" @for case in $(TESTCASES); do \ - echo -n "$$case "; \ + printf %s "$$case "; \ $(SIMG) $$case; \ done From 90880ff107ecaada2a06a823dc5fa652f6e37a62 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 5 Jul 2017 13:57:30 +0100 Subject: [PATCH 61/85] block: add bdrv_measure() API bdrv_measure() provides a conservative maximum for the size of a new image. This information is handy if storage needs to be allocated (e.g. a SAN or an LVM volume) ahead of time. Signed-off-by: Stefan Hajnoczi Reviewed-by: Alberto Garcia Message-id: 20170705125738.8777-2-stefanha@redhat.com Signed-off-by: Max Reitz --- block.c | 35 +++++++++++++++++++++++++++++++++++ include/block/block.h | 2 ++ include/block/block_int.h | 2 ++ qapi/block-core.json | 25 +++++++++++++++++++++++++ 4 files changed, 64 insertions(+) diff --git a/block.c b/block.c index 913bb43289..162e9d9087 100644 --- a/block.c +++ b/block.c @@ -3463,6 +3463,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. */ diff --git a/include/block/block.h b/include/block/block.h index f0fdbe8006..96edc85129 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -306,6 +306,8 @@ int bdrv_truncate(BdrvChild *child, int64_t offset, 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); diff --git a/include/block/block_int.h b/include/block/block_int.h index 58d4ffd533..d0cd8a3c58 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -209,6 +209,8 @@ struct BlockDriver { 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); diff --git a/qapi/block-core.json b/qapi/block-core.json index 4bf11e8b8b..c437aa50ef 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -487,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: # From a843a22a82e0b2bf5841af8a074066ea1d18997a Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 5 Jul 2017 13:57:31 +0100 Subject: [PATCH 62/85] raw-format: add bdrv_measure() support Maximum size calculation is trivial for the raw format: it's just the requested image size (because there is no metadata). Signed-off-by: Stefan Hajnoczi Reviewed-by: Alberto Garcia Message-id: 20170705125738.8777-3-stefanha@redhat.com Signed-off-by: Max Reitz --- block/raw-format.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/block/raw-format.c b/block/raw-format.c index 1ea8c2d7ff..a1622c6219 100644 --- a/block/raw-format.c +++ b/block/raw-format.c @@ -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); @@ -479,6 +504,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, From 95c67e3bd747b119aa0a902778e1c20fd7fded7f Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 5 Jul 2017 13:57:32 +0100 Subject: [PATCH 63/85] qcow2: extract preallocation calculation function Calculating the preallocated image size will be needed to implement .bdrv_measure(). Extract the code out into a separate function. Signed-off-by: Stefan Hajnoczi Reviewed-by: Alberto Garcia Message-id: 20170705125738.8777-4-stefanha@redhat.com Signed-off-by: Max Reitz --- block/qcow2.c | 136 ++++++++++++++++++++++++++++---------------------- 1 file changed, 77 insertions(+), 59 deletions(-) diff --git a/block/qcow2.c b/block/qcow2.c index 9d3c70eadb..0506c7eb04 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -2537,6 +2537,80 @@ static int preallocate(BlockDriverState *bs) return 0; } +/** + * qcow2_calc_prealloc_size: + * @total_size: virtual disk size in bytes + * @cluster_size: cluster size in bytes + * @refcount_order: refcount bits power-of-2 exponent + * + * Returns: Total number of bytes required for the fully allocated image + * (including metadata). + */ +static int64_t qcow2_calc_prealloc_size(int64_t total_size, + size_t cluster_size, + int refcount_order) +{ + /* Note: The following calculation does not need to be exact; if it is a + * bit off, either some bytes will be "leaked" (which is fine) or we + * will need to increase the file size by some bytes (which is fine, + * too, as long as the bulk is allocated here). Therefore, using + * floating point arithmetic is fine. */ + int64_t meta_size = 0; + uint64_t nreftablee, nrefblocke, nl1e, nl2e, refblock_count; + int64_t aligned_total_size = align_offset(total_size, cluster_size); + int cluster_bits = ctz32(cluster_size); + int refblock_bits, refblock_size; + /* refcount entry size in bytes */ + double rces = (1 << refcount_order) / 8.; + + /* see qcow2_open() */ + refblock_bits = cluster_bits - (refcount_order - 3); + refblock_size = 1 << refblock_bits; + + /* header: 1 cluster */ + meta_size += cluster_size; + + /* total size of L2 tables */ + nl2e = aligned_total_size / cluster_size; + nl2e = align_offset(nl2e, cluster_size / sizeof(uint64_t)); + meta_size += nl2e * sizeof(uint64_t); + + /* total size of L1 tables */ + nl1e = nl2e * sizeof(uint64_t) / cluster_size; + nl1e = align_offset(nl1e, cluster_size / sizeof(uint64_t)); + meta_size += nl1e * sizeof(uint64_t); + + /* total size of refcount blocks + * + * note: every host cluster is reference-counted, including metadata + * (even refcount blocks are recursively included). + * Let: + * a = total_size (this is the guest disk size) + * m = meta size not including refcount blocks and refcount tables + * c = cluster size + * y1 = number of refcount blocks entries + * y2 = meta size including everything + * rces = refcount entry size in bytes + * then, + * y1 = (y2 + a)/c + * y2 = y1 * rces + y1 * rces * sizeof(u64) / c + m + * we can get y1: + * y1 = (a + m) / (c - rces - rces * sizeof(u64) / c) + */ + nrefblocke = (aligned_total_size + meta_size + cluster_size) + / (cluster_size - rces - rces * sizeof(uint64_t) + / cluster_size); + refblock_count = DIV_ROUND_UP(nrefblocke, refblock_size); + meta_size += refblock_count * cluster_size; + + /* total size of refcount tables */ + nreftablee = align_offset(refblock_count, + cluster_size / sizeof(uint64_t)); + meta_size += nreftablee * sizeof(uint64_t); + + return meta_size + aligned_total_size; +} + static int qcow2_create2(const char *filename, int64_t total_size, const char *backing_file, const char *backing_format, int flags, size_t cluster_size, PreallocMode prealloc, @@ -2575,65 +2649,9 @@ static int qcow2_create2(const char *filename, int64_t total_size, int ret; if (prealloc == PREALLOC_MODE_FULL || prealloc == PREALLOC_MODE_FALLOC) { - /* Note: The following calculation does not need to be exact; if it is a - * bit off, either some bytes will be "leaked" (which is fine) or we - * will need to increase the file size by some bytes (which is fine, - * too, as long as the bulk is allocated here). Therefore, using - * floating point arithmetic is fine. */ - int64_t meta_size = 0; - uint64_t nreftablee, nrefblocke, nl1e, nl2e, refblock_count; - int64_t aligned_total_size = align_offset(total_size, cluster_size); - int refblock_bits, refblock_size; - /* refcount entry size in bytes */ - double rces = (1 << refcount_order) / 8.; - - /* see qcow2_open() */ - refblock_bits = cluster_bits - (refcount_order - 3); - refblock_size = 1 << refblock_bits; - - /* header: 1 cluster */ - meta_size += cluster_size; - - /* total size of L2 tables */ - nl2e = aligned_total_size / cluster_size; - nl2e = align_offset(nl2e, cluster_size / sizeof(uint64_t)); - meta_size += nl2e * sizeof(uint64_t); - - /* total size of L1 tables */ - nl1e = nl2e * sizeof(uint64_t) / cluster_size; - nl1e = align_offset(nl1e, cluster_size / sizeof(uint64_t)); - meta_size += nl1e * sizeof(uint64_t); - - /* total size of refcount blocks - * - * note: every host cluster is reference-counted, including metadata - * (even refcount blocks are recursively included). - * Let: - * a = total_size (this is the guest disk size) - * m = meta size not including refcount blocks and refcount tables - * c = cluster size - * y1 = number of refcount blocks entries - * y2 = meta size including everything - * rces = refcount entry size in bytes - * then, - * y1 = (y2 + a)/c - * y2 = y1 * rces + y1 * rces * sizeof(u64) / c + m - * we can get y1: - * y1 = (a + m) / (c - rces - rces * sizeof(u64) / c) - */ - nrefblocke = (aligned_total_size + meta_size + cluster_size) - / (cluster_size - rces - rces * sizeof(uint64_t) - / cluster_size); - refblock_count = DIV_ROUND_UP(nrefblocke, refblock_size); - meta_size += refblock_count * cluster_size; - - /* total size of refcount tables */ - nreftablee = align_offset(refblock_count, - cluster_size / sizeof(uint64_t)); - meta_size += nreftablee * sizeof(uint64_t); - - qemu_opt_set_number(opts, BLOCK_OPT_SIZE, - aligned_total_size + meta_size, &error_abort); + int64_t prealloc_size = + qcow2_calc_prealloc_size(total_size, cluster_size, refcount_order); + qemu_opt_set_number(opts, BLOCK_OPT_SIZE, prealloc_size, &error_abort); qemu_opt_set(opts, BLOCK_OPT_PREALLOC, PreallocMode_lookup[prealloc], &error_abort); } From 7c5bcc42120119bb46d8b2a422053467bcc7291c Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 5 Jul 2017 13:57:33 +0100 Subject: [PATCH 64/85] qcow2: make refcount size calculation conservative The refcount metadata size calculation is inaccurate and can produce numbers that are too small. This is bad because we should calculate a conservative number - one that is guaranteed to be large enough. This patch switches the approach to a fixed point calculation because the existing equation is hard to solve when inaccuracies are taken care of. Signed-off-by: Stefan Hajnoczi Reviewed-by: Alberto Garcia Message-id: 20170705125738.8777-5-stefanha@redhat.com Signed-off-by: Max Reitz --- block/qcow2.c | 83 ++++++++++++++++++++++++++------------------------- 1 file changed, 42 insertions(+), 41 deletions(-) diff --git a/block/qcow2.c b/block/qcow2.c index 0506c7eb04..eb57013e81 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -2537,6 +2537,43 @@ static int preallocate(BlockDriverState *bs) return 0; } +/* qcow2_refcount_metadata_size: + * @clusters: number of clusters to refcount (including data and L1/L2 tables) + * @cluster_size: size of a cluster, in bytes + * @refcount_order: refcount bits power-of-2 exponent + * + * Returns: Number of bytes required for refcount blocks and table metadata. + */ +static int64_t qcow2_refcount_metadata_size(int64_t clusters, + size_t cluster_size, + int refcount_order) +{ + /* + * Every host cluster is reference-counted, including metadata (even + * refcount metadata is recursively included). + * + * An accurate formula for the size of refcount metadata size is difficult + * to derive. An easier method of calculation is finding the fixed point + * where no further refcount blocks or table clusters are required to + * reference count every cluster. + */ + int64_t blocks_per_table_cluster = cluster_size / sizeof(uint64_t); + int64_t refcounts_per_block = cluster_size * 8 / (1 << refcount_order); + int64_t table = 0; /* number of refcount table clusters */ + int64_t blocks = 0; /* number of refcount block clusters */ + int64_t last; + int64_t n = 0; + + do { + last = n; + blocks = DIV_ROUND_UP(clusters + table + blocks, refcounts_per_block); + table = DIV_ROUND_UP(blocks, blocks_per_table_cluster); + n = clusters + blocks + table; + } while (n != last); + + return (blocks + table) * cluster_size; +} + /** * qcow2_calc_prealloc_size: * @total_size: virtual disk size in bytes @@ -2550,22 +2587,9 @@ static int64_t qcow2_calc_prealloc_size(int64_t total_size, size_t cluster_size, int refcount_order) { - /* Note: The following calculation does not need to be exact; if it is a - * bit off, either some bytes will be "leaked" (which is fine) or we - * will need to increase the file size by some bytes (which is fine, - * too, as long as the bulk is allocated here). Therefore, using - * floating point arithmetic is fine. */ int64_t meta_size = 0; - uint64_t nreftablee, nrefblocke, nl1e, nl2e, refblock_count; + uint64_t nl1e, nl2e; int64_t aligned_total_size = align_offset(total_size, cluster_size); - int cluster_bits = ctz32(cluster_size); - int refblock_bits, refblock_size; - /* refcount entry size in bytes */ - double rces = (1 << refcount_order) / 8.; - - /* see qcow2_open() */ - refblock_bits = cluster_bits - (refcount_order - 3); - refblock_size = 1 << refblock_bits; /* header: 1 cluster */ meta_size += cluster_size; @@ -2580,33 +2604,10 @@ static int64_t qcow2_calc_prealloc_size(int64_t total_size, nl1e = align_offset(nl1e, cluster_size / sizeof(uint64_t)); meta_size += nl1e * sizeof(uint64_t); - /* total size of refcount blocks - * - * note: every host cluster is reference-counted, including metadata - * (even refcount blocks are recursively included). - * Let: - * a = total_size (this is the guest disk size) - * m = meta size not including refcount blocks and refcount tables - * c = cluster size - * y1 = number of refcount blocks entries - * y2 = meta size including everything - * rces = refcount entry size in bytes - * then, - * y1 = (y2 + a)/c - * y2 = y1 * rces + y1 * rces * sizeof(u64) / c + m - * we can get y1: - * y1 = (a + m) / (c - rces - rces * sizeof(u64) / c) - */ - nrefblocke = (aligned_total_size + meta_size + cluster_size) - / (cluster_size - rces - rces * sizeof(uint64_t) - / cluster_size); - refblock_count = DIV_ROUND_UP(nrefblocke, refblock_size); - meta_size += refblock_count * cluster_size; - - /* total size of refcount tables */ - nreftablee = align_offset(refblock_count, - cluster_size / sizeof(uint64_t)); - meta_size += nreftablee * sizeof(uint64_t); + /* total size of refcount table and blocks */ + meta_size += qcow2_refcount_metadata_size( + (meta_size + aligned_total_size) / cluster_size, + cluster_size, refcount_order); return meta_size + aligned_total_size; } From 0eb4a8c1df6db29e835daeb954352bfaa8994374 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 5 Jul 2017 13:57:34 +0100 Subject: [PATCH 65/85] qcow2: extract image creation option parsing The image creation options parsed by qcow2_create() are also needed to implement .bdrv_measure(). Extract the parsing code, including input validation. Signed-off-by: Stefan Hajnoczi Reviewed-by: Alberto Garcia Message-id: 20170705125738.8777-6-stefanha@redhat.com Signed-off-by: Max Reitz --- block/qcow2.c | 109 +++++++++++++++++++++++++++++++++----------------- 1 file changed, 73 insertions(+), 36 deletions(-) diff --git a/block/qcow2.c b/block/qcow2.c index eb57013e81..db8d81fdc4 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -2612,24 +2612,73 @@ static int64_t qcow2_calc_prealloc_size(int64_t total_size, return meta_size + aligned_total_size; } -static int qcow2_create2(const char *filename, int64_t total_size, - const char *backing_file, const char *backing_format, - int flags, size_t cluster_size, PreallocMode prealloc, - QemuOpts *opts, int version, int refcount_order, - const char *encryptfmt, Error **errp) +static size_t qcow2_opt_get_cluster_size_del(QemuOpts *opts, Error **errp) { + size_t cluster_size; int cluster_bits; - QDict *options; - /* Calculate cluster_bits */ + cluster_size = qemu_opt_get_size_del(opts, BLOCK_OPT_CLUSTER_SIZE, + DEFAULT_CLUSTER_SIZE); cluster_bits = ctz32(cluster_size); if (cluster_bits < MIN_CLUSTER_BITS || cluster_bits > MAX_CLUSTER_BITS || (1 << cluster_bits) != cluster_size) { error_setg(errp, "Cluster size must be a power of two between %d and " "%dk", 1 << MIN_CLUSTER_BITS, 1 << (MAX_CLUSTER_BITS - 10)); - return -EINVAL; + return 0; } + return cluster_size; +} + +static int qcow2_opt_get_version_del(QemuOpts *opts, Error **errp) +{ + char *buf; + int ret; + + buf = qemu_opt_get_del(opts, BLOCK_OPT_COMPAT_LEVEL); + if (!buf) { + ret = 3; /* default */ + } else if (!strcmp(buf, "0.10")) { + ret = 2; + } else if (!strcmp(buf, "1.1")) { + ret = 3; + } else { + error_setg(errp, "Invalid compatibility level: '%s'", buf); + ret = -EINVAL; + } + g_free(buf); + return ret; +} + +static uint64_t qcow2_opt_get_refcount_bits_del(QemuOpts *opts, int version, + Error **errp) +{ + uint64_t refcount_bits; + + refcount_bits = qemu_opt_get_number_del(opts, BLOCK_OPT_REFCOUNT_BITS, 16); + if (refcount_bits > 64 || !is_power_of_2(refcount_bits)) { + error_setg(errp, "Refcount width must be a power of two and may not " + "exceed 64 bits"); + return 0; + } + + if (version < 3 && refcount_bits != 16) { + error_setg(errp, "Different refcount widths than 16 bits require " + "compatibility level 1.1 or above (use compat=1.1 or " + "greater)"); + return 0; + } + + return refcount_bits; +} + +static int qcow2_create2(const char *filename, int64_t total_size, + const char *backing_file, const char *backing_format, + int flags, size_t cluster_size, PreallocMode prealloc, + QemuOpts *opts, int version, int refcount_order, + const char *encryptfmt, Error **errp) +{ + QDict *options; /* * Open the image file and write a minimal qcow2 header. @@ -2679,7 +2728,7 @@ static int qcow2_create2(const char *filename, int64_t total_size, *header = (QCowHeader) { .magic = cpu_to_be32(QCOW_MAGIC), .version = cpu_to_be32(version), - .cluster_bits = cpu_to_be32(cluster_bits), + .cluster_bits = cpu_to_be32(ctz32(cluster_size)), .size = cpu_to_be64(0), .l1_table_offset = cpu_to_be64(0), .l1_size = cpu_to_be32(0), @@ -2826,8 +2875,8 @@ static int qcow2_create(const char *filename, QemuOpts *opts, Error **errp) int flags = 0; size_t cluster_size = DEFAULT_CLUSTER_SIZE; PreallocMode prealloc; - int version = 3; - uint64_t refcount_bits = 16; + int version; + uint64_t refcount_bits; int refcount_order; const char *encryptfmt = NULL; Error *local_err = NULL; @@ -2849,8 +2898,12 @@ static int qcow2_create(const char *filename, QemuOpts *opts, Error **errp) } else if (qemu_opt_get_bool_del(opts, BLOCK_OPT_ENCRYPT, false)) { encryptfmt = "aes"; } - cluster_size = qemu_opt_get_size_del(opts, BLOCK_OPT_CLUSTER_SIZE, - DEFAULT_CLUSTER_SIZE); + cluster_size = qcow2_opt_get_cluster_size_del(opts, &local_err); + if (local_err) { + error_propagate(errp, local_err); + ret = -EINVAL; + goto finish; + } buf = qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC); prealloc = qapi_enum_parse(PreallocMode_lookup, buf, PREALLOC_MODE__MAX, PREALLOC_MODE_OFF, @@ -2860,16 +2913,10 @@ static int qcow2_create(const char *filename, QemuOpts *opts, Error **errp) ret = -EINVAL; goto finish; } - g_free(buf); - buf = qemu_opt_get_del(opts, BLOCK_OPT_COMPAT_LEVEL); - if (!buf) { - /* keep the default */ - } else if (!strcmp(buf, "0.10")) { - version = 2; - } else if (!strcmp(buf, "1.1")) { - version = 3; - } else { - error_setg(errp, "Invalid compatibility level: '%s'", buf); + + version = qcow2_opt_get_version_del(opts, &local_err); + if (local_err) { + error_propagate(errp, local_err); ret = -EINVAL; goto finish; } @@ -2892,19 +2939,9 @@ static int qcow2_create(const char *filename, QemuOpts *opts, Error **errp) goto finish; } - refcount_bits = qemu_opt_get_number_del(opts, BLOCK_OPT_REFCOUNT_BITS, - refcount_bits); - if (refcount_bits > 64 || !is_power_of_2(refcount_bits)) { - error_setg(errp, "Refcount width must be a power of two and may not " - "exceed 64 bits"); - ret = -EINVAL; - goto finish; - } - - if (version < 3 && refcount_bits != 16) { - error_setg(errp, "Different refcount widths than 16 bits require " - "compatibility level 1.1 or above (use compat=1.1 or " - "greater)"); + refcount_bits = qcow2_opt_get_refcount_bits_del(opts, version, &local_err); + if (local_err) { + error_propagate(errp, local_err); ret = -EINVAL; goto finish; } From c501c35220856621e9677ba9e6a556948d49778e Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 5 Jul 2017 13:57:35 +0100 Subject: [PATCH 66/85] qcow2: add bdrv_measure() support Use qcow2_calc_prealloc_size() to get the required file size. Signed-off-by: Stefan Hajnoczi Reviewed-by: Alberto Garcia Message-id: 20170705125738.8777-7-stefanha@redhat.com Signed-off-by: Max Reitz --- block/qcow2.c | 137 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 137 insertions(+) diff --git a/block/qcow2.c b/block/qcow2.c index db8d81fdc4..52dc6bf3c9 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -3426,6 +3426,142 @@ static coroutine_fn int qcow2_co_flush_to_os(BlockDriverState *bs) return 0; } +static BlockMeasureInfo *qcow2_measure(QemuOpts *opts, BlockDriverState *in_bs, + Error **errp) +{ + Error *local_err = NULL; + BlockMeasureInfo *info; + uint64_t required = 0; /* bytes that contribute to required size */ + uint64_t virtual_size; /* disk size as seen by guest */ + uint64_t refcount_bits; + uint64_t l2_tables; + size_t cluster_size; + int version; + char *optstr; + PreallocMode prealloc; + bool has_backing_file; + + /* Parse image creation options */ + cluster_size = qcow2_opt_get_cluster_size_del(opts, &local_err); + if (local_err) { + goto err; + } + + version = qcow2_opt_get_version_del(opts, &local_err); + if (local_err) { + goto err; + } + + refcount_bits = qcow2_opt_get_refcount_bits_del(opts, version, &local_err); + if (local_err) { + goto err; + } + + optstr = qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC); + prealloc = qapi_enum_parse(PreallocMode_lookup, optstr, + PREALLOC_MODE__MAX, PREALLOC_MODE_OFF, + &local_err); + g_free(optstr); + if (local_err) { + goto err; + } + + optstr = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FILE); + has_backing_file = !!optstr; + g_free(optstr); + + virtual_size = align_offset(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0), + cluster_size); + + /* Check that virtual disk size is valid */ + l2_tables = DIV_ROUND_UP(virtual_size / cluster_size, + cluster_size / sizeof(uint64_t)); + if (l2_tables * sizeof(uint64_t) > QCOW_MAX_L1_SIZE) { + error_setg(&local_err, "The image size is too large " + "(try using a larger cluster size)"); + goto err; + } + + /* Account for input image */ + if (in_bs) { + int64_t ssize = bdrv_getlength(in_bs); + if (ssize < 0) { + error_setg_errno(&local_err, -ssize, + "Unable to get image virtual_size"); + goto err; + } + + virtual_size = align_offset(ssize, cluster_size); + + if (has_backing_file) { + /* We don't how much of the backing chain is shared by the input + * image and the new image file. In the worst case the new image's + * backing file has nothing in common with the input image. Be + * conservative and assume all clusters need to be written. + */ + required = virtual_size; + } else { + int cluster_sectors = cluster_size / BDRV_SECTOR_SIZE; + int64_t sector_num; + int pnum = 0; + + for (sector_num = 0; + sector_num < ssize / BDRV_SECTOR_SIZE; + sector_num += pnum) { + int nb_sectors = MAX(ssize / BDRV_SECTOR_SIZE - sector_num, + INT_MAX); + BlockDriverState *file; + int64_t ret; + + ret = bdrv_get_block_status_above(in_bs, NULL, + sector_num, nb_sectors, + &pnum, &file); + if (ret < 0) { + error_setg_errno(&local_err, -ret, + "Unable to get block status"); + goto err; + } + + if (ret & BDRV_BLOCK_ZERO) { + /* Skip zero regions (safe with no backing file) */ + } else if ((ret & (BDRV_BLOCK_DATA | BDRV_BLOCK_ALLOCATED)) == + (BDRV_BLOCK_DATA | BDRV_BLOCK_ALLOCATED)) { + /* Extend pnum to end of cluster for next iteration */ + pnum = ROUND_UP(sector_num + pnum, cluster_sectors) - + sector_num; + + /* Count clusters we've seen */ + required += (sector_num % cluster_sectors + pnum) * + BDRV_SECTOR_SIZE; + } + } + } + } + + /* Take into account preallocation. Nothing special is needed for + * PREALLOC_MODE_METADATA since metadata is always counted. + */ + if (prealloc == PREALLOC_MODE_FULL || prealloc == PREALLOC_MODE_FALLOC) { + required = virtual_size; + } + + info = g_new(BlockMeasureInfo, 1); + info->fully_allocated = + qcow2_calc_prealloc_size(virtual_size, cluster_size, + ctz32(refcount_bits)); + + /* Remove data clusters that are not required. This overestimates the + * required size because metadata needed for the fully allocated file is + * still counted. + */ + info->required = info->fully_allocated - virtual_size + required; + return info; + +err: + error_propagate(errp, local_err); + return NULL; +} + static int qcow2_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) { BDRVQcow2State *s = bs->opaque; @@ -4024,6 +4160,7 @@ BlockDriver bdrv_qcow2 = { .bdrv_snapshot_delete = qcow2_snapshot_delete, .bdrv_snapshot_list = qcow2_snapshot_list, .bdrv_snapshot_load_tmp = qcow2_snapshot_load_tmp, + .bdrv_measure = qcow2_measure, .bdrv_get_info = qcow2_get_info, .bdrv_get_specific_info = qcow2_get_specific_info, From fd03c2b8fbf463f92413ed70a978bf70ebbc74c7 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 5 Jul 2017 13:57:36 +0100 Subject: [PATCH 67/85] qemu-img: add measure subcommand The measure subcommand calculates the size required by a new image file. This can be used by users or management tools that need to allocate space on an LVM volume, SAN LUN, etc before creating or converting an image file. Suggested-by: Maor Lipchuk Signed-off-by: Stefan Hajnoczi Reviewed-by: Alberto Garcia Message-id: 20170705125738.8777-8-stefanha@redhat.com Signed-off-by: Max Reitz --- qemu-img-cmds.hx | 6 ++ qemu-img.c | 234 +++++++++++++++++++++++++++++++++++++++++++++++ qemu-img.texi | 30 ++++++ 3 files changed, 270 insertions(+) diff --git a/qemu-img-cmds.hx b/qemu-img-cmds.hx index a39fcdba71..ac5946bc4f 100644 --- a/qemu-img-cmds.hx +++ b/qemu-img-cmds.hx @@ -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 diff --git a/qemu-img.c b/qemu-img.c index 7f1de74c13..930ae88a0d 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -61,6 +61,7 @@ enum { OPTION_FLUSH_INTERVAL = 261, OPTION_NO_DRAIN = 262, OPTION_TARGET_IMAGE_OPTS = 263, + OPTION_SIZE = 264, }; typedef enum OutputFormat { @@ -4419,6 +4420,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) \ diff --git a/qemu-img.texi b/qemu-img.texi index f335139217..a2f45199d2 100644 --- a/qemu-img.texi +++ b/qemu-img.texi @@ -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}. From 217a0683b754fed7f7c7ad5c241a7ddb52506844 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 5 Jul 2017 13:57:37 +0100 Subject: [PATCH 68/85] qemu-iotests: support per-format golden output files Some tests produce format-dependent output. Either the difference is filtered out and ignored, or the test case is format-specific so we don't need to worry about per-format output differences. There is a third case: the test script is the same for all image formats and the format-dependent output is relevant. An ugly workaround is to copy-paste the test into multiple per-format test cases. This duplicates code and is not maintainable. This patch allows test cases to add per-format golden output files so a single test case can work correctly when format-dependent output must be checked: 123.out.qcow2 123.out.raw 123.out.vmdk ... This naming scheme is not composable with 123.out.nocache or 123.pc.out, two other scenarios where output files are split. I don't think it matters since few test cases need these features. Signed-off-by: Stefan Hajnoczi Reviewed-by: Alberto Garcia Message-id: 20170705125738.8777-9-stefanha@redhat.com Signed-off-by: Max Reitz --- tests/qemu-iotests/check | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/qemu-iotests/check b/tests/qemu-iotests/check index 9ded37c128..2a55ec9ada 100755 --- a/tests/qemu-iotests/check +++ b/tests/qemu-iotests/check @@ -338,6 +338,11 @@ do reference="$reference_machine" fi + reference_format="$source_iotests/$seq.out.$IMGFMT" + if [ -f "$reference_format" ]; then + reference="$reference_format" + fi + if [ "$CACHEMODE" = "none" ]; then [ -f "$source_iotests/$seq.out.nocache" ] && reference="$source_iotests/$seq.out.nocache" fi From 32a1681adc44f52e7c8a19408cd3be8452a0897b Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 5 Jul 2017 13:57:38 +0100 Subject: [PATCH 69/85] iotests: add test 178 for qemu-img measure Signed-off-by: Stefan Hajnoczi Reviewed-by: Alberto Garcia Message-id: 20170705125738.8777-10-stefanha@redhat.com Signed-off-by: Max Reitz --- tests/qemu-iotests/178 | 170 ++++++++++++++++++ tests/qemu-iotests/178.out.qcow2 | 286 +++++++++++++++++++++++++++++++ tests/qemu-iotests/178.out.raw | 158 +++++++++++++++++ tests/qemu-iotests/group | 1 + 4 files changed, 615 insertions(+) create mode 100755 tests/qemu-iotests/178 create mode 100644 tests/qemu-iotests/178.out.qcow2 create mode 100644 tests/qemu-iotests/178.out.raw diff --git a/tests/qemu-iotests/178 b/tests/qemu-iotests/178 new file mode 100755 index 0000000000..6af52c653a --- /dev/null +++ b/tests/qemu-iotests/178 @@ -0,0 +1,170 @@ +#!/bin/bash +# +# qemu-img measure sub-command tests +# +# 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 . +# + +# creator +owner=stefanha@redhat.com + +seq=`basename $0` +echo "QA output created by $seq" + +here=`pwd` +status=1 # failure is the default! + +_cleanup() +{ + _cleanup_test_img + rm -f "$TEST_IMG.converted" +} +trap "_cleanup; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter +. ./common.pattern + +_supported_fmt raw qcow2 +_supported_proto file +_supported_os Linux + +echo "== Input validation ==" +echo + +_make_test_img 1G + +$QEMU_IMG measure # missing arguments +$QEMU_IMG measure --size 2G "$TEST_IMG" # only one allowed +$QEMU_IMG measure "$TEST_IMG" a # only one filename allowed +$QEMU_IMG measure --object secret,id=sec0,data=MTIzNDU2,format=base64 # missing filename +$QEMU_IMG measure --image-opts # missing filename +$QEMU_IMG measure -f qcow2 # missing filename +$QEMU_IMG measure -l snap1 # missing filename +$QEMU_IMG measure -o , # invalid option list +$QEMU_IMG measure -l snapshot.foo # invalid snapshot option +$QEMU_IMG measure --output foo # invalid output format +$QEMU_IMG measure --size -1 # invalid image size +$QEMU_IMG measure -O foo "$TEST_IMG" # unknown image file format + +make_test_img_with_fmt() { + # Shadow global variables within this function + local IMGFMT="$1" IMGOPTS="" + _make_test_img "$2" +} + +qemu_io_with_fmt() { + # Shadow global variables within this function + local QEMU_IO_OPTIONS=$(echo "$QEMU_IO_OPTIONS" | sed "s/-f $IMGFMT/-f $1/") + shift + $QEMU_IO "$@" +} + +# The proof is in the pudding: converted image size cannot be larger than the +# required size. +# +# Note: if a change to the image format code causes the file size to change, +# then this test fails! This is good because it's a reminder to check that the +# required size is still at least as big as the actual converted file size. +convert_and_show_size() { + local fmt="$1" + shift + $QEMU_IMG convert -f "$fmt" -O "$IMGFMT" "$TEST_IMG" "$@" "$TEST_IMG.converted" + stat -c "converted image file size in bytes: %s" "$TEST_IMG.converted" +} + +for ofmt in human json; do + echo + echo "== Size calculation for a new file ($ofmt) ==" + echo + + # Try a few interesting sizes + $QEMU_IMG measure --output=$ofmt -O "$IMGFMT" --size 0 + $QEMU_IMG measure --output=$ofmt -O "$IMGFMT" --size 2G + $QEMU_IMG measure --output=$ofmt -O "$IMGFMT" --size 64G + $QEMU_IMG measure --output=$ofmt -O "$IMGFMT" --size 256G + $QEMU_IMG measure --output=$ofmt -O "$IMGFMT" --size 1T + $QEMU_IMG measure --output=$ofmt -O "$IMGFMT" --size 2P + $QEMU_IMG measure --output=$ofmt -O "$IMGFMT" --size 7E + + # Always test the raw input files but also IMGFMT + for fmt in $(echo -e "raw\n$IMGFMT\n" | sort -u); do + echo + echo "== Empty $fmt input image ($ofmt) ==" + echo + make_test_img_with_fmt "$fmt" 0 + $QEMU_IMG measure --output=$ofmt -f "$fmt" -O "$IMGFMT" "$TEST_IMG" + echo + convert_and_show_size "$fmt" + + echo + echo "== $fmt input image with data ($ofmt) ==" + echo + make_test_img_with_fmt "$fmt" 1G + $QEMU_IMG measure --output=$ofmt -f "$fmt" -O "$IMGFMT" "$TEST_IMG" + qemu_io_with_fmt "$fmt" -c "write 512 512" "$TEST_IMG" | _filter_qemu_io + qemu_io_with_fmt "$fmt" -c "write 64K 64K" "$TEST_IMG" | _filter_qemu_io + if [ "$fmt" = "qcow2" ]; then + $QEMU_IMG snapshot -c snapshot1 "$TEST_IMG" + fi + qemu_io_with_fmt "$fmt" -c "write 128M 63K" "$TEST_IMG" | _filter_qemu_io + $QEMU_IMG measure --output=$ofmt -f "$fmt" -O "$IMGFMT" "$TEST_IMG" + echo + convert_and_show_size "$fmt" + + if [ "$fmt" = "qcow2" ]; then + echo + echo "== $fmt input image with internal snapshot ($ofmt) ==" + echo + $QEMU_IMG measure --output=$ofmt -f "$fmt" -l snapshot1 \ + -O "$IMGFMT" "$TEST_IMG" + echo + convert_and_show_size "$fmt" -l snapshot1 + fi + + if [ "$IMGFMT" = "qcow2" ]; then + echo + echo "== $fmt input image and a backing file ($ofmt) ==" + echo + # The backing file doesn't need to exist :) + $QEMU_IMG measure --output=$ofmt -o backing_file=x \ + -f "$fmt" -O "$IMGFMT" "$TEST_IMG" + fi + + echo + echo "== $fmt input image and preallocation ($ofmt) ==" + echo + $QEMU_IMG measure --output=$ofmt -o preallocation=full \ + -f "$fmt" -O "$IMGFMT" "$TEST_IMG" + echo + convert_and_show_size "$fmt" -o preallocation=full + + echo + echo "== Fully-allocated $fmt input image ($ofmt) ==" + echo + make_test_img_with_fmt "$fmt" 8M + qemu_io_with_fmt "$fmt" -c "write 0 8M" "$TEST_IMG" | _filter_qemu_io + $QEMU_IMG measure --output=$ofmt -f "$fmt" -O "$IMGFMT" "$TEST_IMG" + echo + convert_and_show_size "$fmt" + done +done + +# success, all done +echo "*** done" +rm -f $seq.full +status=0 diff --git a/tests/qemu-iotests/178.out.qcow2 b/tests/qemu-iotests/178.out.qcow2 new file mode 100644 index 0000000000..d42d4a4597 --- /dev/null +++ b/tests/qemu-iotests/178.out.qcow2 @@ -0,0 +1,286 @@ +QA output created by 178 +== Input validation == + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 +qemu-img: Either --size N or one filename must be specified. +qemu-img: --size N cannot be used together with a filename. +qemu-img: At most one filename argument is allowed. +qemu-img: --object, --image-opts, -f, and -l require a filename argument. +qemu-img: --object, --image-opts, -f, and -l require a filename argument. +qemu-img: --object, --image-opts, -f, and -l require a filename argument. +qemu-img: --object, --image-opts, -f, and -l require a filename argument. +qemu-img: Invalid option list: , +qemu-img: Invalid parameter 'snapshot.foo' +qemu-img: Failed in parsing snapshot param 'snapshot.foo' +qemu-img: --output must be used with human or json as argument. +qemu-img: Image size must be less than 8 EiB! +qemu-img: Unknown file format 'foo' + +== Size calculation for a new file (human) == + +required size: 196608 +fully allocated size: 196608 +required size: 589824 +fully allocated size: 2148073472 +required size: 10747904 +fully allocated size: 68730224640 +required size: 42205184 +fully allocated size: 274920112128 +required size: 168034304 +fully allocated size: 1099679662080 +required size: 343650009088 +fully allocated size: 2252143463694336 +qemu-img: The image size is too large (try using a larger cluster size) + +== Empty qcow2 input image (human) == + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=0 +required size: 196608 +fully allocated size: 196608 + +converted image file size in bytes: 196608 + +== qcow2 input image with data (human) == + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 +required size: 393216 +fully allocated size: 1074135040 +wrote 512/512 bytes at offset 512 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote 65536/65536 bytes at offset 65536 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote 64512/64512 bytes at offset 134217728 +63 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +required size: 589824 +fully allocated size: 1074135040 + +converted image file size in bytes: 524288 + +== qcow2 input image with internal snapshot (human) == + +required size: 524288 +fully allocated size: 1074135040 + +converted image file size in bytes: 458752 + +== qcow2 input image and a backing file (human) == + +required size: 1074135040 +fully allocated size: 1074135040 + +== qcow2 input image and preallocation (human) == + +required size: 1074135040 +fully allocated size: 1074135040 + +converted image file size in bytes: 1074135040 + +== Fully-allocated qcow2 input image (human) == + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=8388608 +wrote 8388608/8388608 bytes at offset 0 +8 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +required size: 8716288 +fully allocated size: 8716288 + +converted image file size in bytes: 8716288 + +== Empty raw input image (human) == + +Formatting 'TEST_DIR/t.qcow2', fmt=IMGFMT size=0 +required size: 196608 +fully allocated size: 196608 + +converted image file size in bytes: 196608 + +== raw input image with data (human) == + +Formatting 'TEST_DIR/t.qcow2', fmt=IMGFMT size=1073741824 +required size: 393216 +fully allocated size: 1074135040 +wrote 512/512 bytes at offset 512 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote 65536/65536 bytes at offset 65536 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote 64512/64512 bytes at offset 134217728 +63 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +required size: 589824 +fully allocated size: 1074135040 + +converted image file size in bytes: 524288 + +== raw input image and a backing file (human) == + +required size: 1074135040 +fully allocated size: 1074135040 + +== raw input image and preallocation (human) == + +required size: 1074135040 +fully allocated size: 1074135040 + +converted image file size in bytes: 1074135040 + +== Fully-allocated raw input image (human) == + +Formatting 'TEST_DIR/t.qcow2', fmt=IMGFMT size=8388608 +wrote 8388608/8388608 bytes at offset 0 +8 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +required size: 8716288 +fully allocated size: 8716288 + +converted image file size in bytes: 8716288 + +== Size calculation for a new file (json) == + +{ + "required": 196608, + "fully-allocated": 196608 +} +{ + "required": 589824, + "fully-allocated": 2148073472 +} +{ + "required": 10747904, + "fully-allocated": 68730224640 +} +{ + "required": 42205184, + "fully-allocated": 274920112128 +} +{ + "required": 168034304, + "fully-allocated": 1099679662080 +} +{ + "required": 343650009088, + "fully-allocated": 2252143463694336 +} +qemu-img: The image size is too large (try using a larger cluster size) + +== Empty qcow2 input image (json) == + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=0 +{ + "required": 196608, + "fully-allocated": 196608 +} + +converted image file size in bytes: 196608 + +== qcow2 input image with data (json) == + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 +{ + "required": 393216, + "fully-allocated": 1074135040 +} +wrote 512/512 bytes at offset 512 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote 65536/65536 bytes at offset 65536 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote 64512/64512 bytes at offset 134217728 +63 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +{ + "required": 589824, + "fully-allocated": 1074135040 +} + +converted image file size in bytes: 524288 + +== qcow2 input image with internal snapshot (json) == + +{ + "required": 524288, + "fully-allocated": 1074135040 +} + +converted image file size in bytes: 458752 + +== qcow2 input image and a backing file (json) == + +{ + "required": 1074135040, + "fully-allocated": 1074135040 +} + +== qcow2 input image and preallocation (json) == + +{ + "required": 1074135040, + "fully-allocated": 1074135040 +} + +converted image file size in bytes: 1074135040 + +== Fully-allocated qcow2 input image (json) == + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=8388608 +wrote 8388608/8388608 bytes at offset 0 +8 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +{ + "required": 8716288, + "fully-allocated": 8716288 +} + +converted image file size in bytes: 8716288 + +== Empty raw input image (json) == + +Formatting 'TEST_DIR/t.qcow2', fmt=IMGFMT size=0 +{ + "required": 196608, + "fully-allocated": 196608 +} + +converted image file size in bytes: 196608 + +== raw input image with data (json) == + +Formatting 'TEST_DIR/t.qcow2', fmt=IMGFMT size=1073741824 +{ + "required": 393216, + "fully-allocated": 1074135040 +} +wrote 512/512 bytes at offset 512 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote 65536/65536 bytes at offset 65536 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote 64512/64512 bytes at offset 134217728 +63 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +{ + "required": 589824, + "fully-allocated": 1074135040 +} + +converted image file size in bytes: 524288 + +== raw input image and a backing file (json) == + +{ + "required": 1074135040, + "fully-allocated": 1074135040 +} + +== raw input image and preallocation (json) == + +{ + "required": 1074135040, + "fully-allocated": 1074135040 +} + +converted image file size in bytes: 1074135040 + +== Fully-allocated raw input image (json) == + +Formatting 'TEST_DIR/t.qcow2', fmt=IMGFMT size=8388608 +wrote 8388608/8388608 bytes at offset 0 +8 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +{ + "required": 8716288, + "fully-allocated": 8716288 +} + +converted image file size in bytes: 8716288 +*** done diff --git a/tests/qemu-iotests/178.out.raw b/tests/qemu-iotests/178.out.raw new file mode 100644 index 0000000000..6478365905 --- /dev/null +++ b/tests/qemu-iotests/178.out.raw @@ -0,0 +1,158 @@ +QA output created by 178 +== Input validation == + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 +qemu-img: Either --size N or one filename must be specified. +qemu-img: --size N cannot be used together with a filename. +qemu-img: At most one filename argument is allowed. +qemu-img: --object, --image-opts, -f, and -l require a filename argument. +qemu-img: --object, --image-opts, -f, and -l require a filename argument. +qemu-img: --object, --image-opts, -f, and -l require a filename argument. +qemu-img: --object, --image-opts, -f, and -l require a filename argument. +qemu-img: Invalid option list: , +qemu-img: Invalid parameter 'snapshot.foo' +qemu-img: Failed in parsing snapshot param 'snapshot.foo' +qemu-img: --output must be used with human or json as argument. +qemu-img: Image size must be less than 8 EiB! +qemu-img: Unknown file format 'foo' + +== Size calculation for a new file (human) == + +required size: 0 +fully allocated size: 0 +required size: 2147483648 +fully allocated size: 2147483648 +required size: 68719476736 +fully allocated size: 68719476736 +required size: 274877906944 +fully allocated size: 274877906944 +required size: 1099511627776 +fully allocated size: 1099511627776 +required size: 2251799813685248 +fully allocated size: 2251799813685248 +required size: 8070450532247928832 +fully allocated size: 8070450532247928832 + +== Empty raw input image (human) == + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=0 +required size: 0 +fully allocated size: 0 + +converted image file size in bytes: 0 + +== raw input image with data (human) == + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 +required size: 1073741824 +fully allocated size: 1073741824 +wrote 512/512 bytes at offset 512 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote 65536/65536 bytes at offset 65536 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote 64512/64512 bytes at offset 134217728 +63 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +required size: 1073741824 +fully allocated size: 1073741824 + +converted image file size in bytes: 1073741824 + +== raw input image and preallocation (human) == + +required size: 1073741824 +fully allocated size: 1073741824 + +converted image file size in bytes: 1073741824 + +== Fully-allocated raw input image (human) == + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=8388608 +wrote 8388608/8388608 bytes at offset 0 +8 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +required size: 8388608 +fully allocated size: 8388608 + +converted image file size in bytes: 8388608 + +== Size calculation for a new file (json) == + +{ + "required": 0, + "fully-allocated": 0 +} +{ + "required": 2147483648, + "fully-allocated": 2147483648 +} +{ + "required": 68719476736, + "fully-allocated": 68719476736 +} +{ + "required": 274877906944, + "fully-allocated": 274877906944 +} +{ + "required": 1099511627776, + "fully-allocated": 1099511627776 +} +{ + "required": 2251799813685248, + "fully-allocated": 2251799813685248 +} +{ + "required": 8070450532247928832, + "fully-allocated": 8070450532247928832 +} + +== Empty raw input image (json) == + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=0 +{ + "required": 0, + "fully-allocated": 0 +} + +converted image file size in bytes: 0 + +== raw input image with data (json) == + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 +{ + "required": 1073741824, + "fully-allocated": 1073741824 +} +wrote 512/512 bytes at offset 512 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote 65536/65536 bytes at offset 65536 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote 64512/64512 bytes at offset 134217728 +63 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +{ + "required": 1073741824, + "fully-allocated": 1073741824 +} + +converted image file size in bytes: 1073741824 + +== raw input image and preallocation (json) == + +{ + "required": 1073741824, + "fully-allocated": 1073741824 +} + +converted image file size in bytes: 1073741824 + +== Fully-allocated raw input image (json) == + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=8388608 +wrote 8388608/8388608 bytes at offset 0 +8 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +{ + "required": 8388608, + "fully-allocated": 8388608 +} + +converted image file size in bytes: 8388608 +*** done diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group index 40bef995fe..8f883f7559 100644 --- a/tests/qemu-iotests/group +++ b/tests/qemu-iotests/group @@ -173,6 +173,7 @@ 175 auto quick 176 rw auto backing 177 rw auto quick +178 auto quick 179 rw auto quick 181 rw auto migration 182 rw auto quick From 8243ccb7433e59a3faa3cca27fb6c40d6da2b37c Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Tue, 13 Jun 2017 22:20:52 +0200 Subject: [PATCH 70/85] block: Add PreallocMode to BD.bdrv_truncate() Add a PreallocMode parameter to the bdrv_truncate() function implemented by each block driver. Currently, we always pass PREALLOC_MODE_OFF and no driver accepts anything else. Signed-off-by: Max Reitz Reviewed-by: Stefan Hajnoczi Message-id: 20170613202107.10125-2-mreitz@redhat.com Signed-off-by: Max Reitz --- block.c | 2 +- block/blkdebug.c | 9 ++++++++- block/crypto.c | 8 +++++++- block/file-posix.c | 9 ++++++++- block/file-win32.c | 9 ++++++++- block/gluster.c | 8 +++++++- block/iscsi.c | 9 ++++++++- block/nfs.c | 9 ++++++++- block/qcow2.c | 9 ++++++++- block/qed.c | 9 ++++++++- block/raw-format.c | 9 ++++++++- block/rbd.c | 9 ++++++++- block/sheepdog.c | 11 +++++++++-- include/block/block_int.h | 3 ++- 14 files changed, 98 insertions(+), 15 deletions(-) diff --git a/block.c b/block.c index 162e9d9087..37e7b3d30a 100644 --- a/block.c +++ b/block.c @@ -3434,7 +3434,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_MODE_OFF, errp); if (ret == 0) { ret = refresh_total_sectors(bs, offset >> BDRV_SECTOR_BITS); bdrv_dirty_bitmap_truncate(bs); diff --git a/block/blkdebug.c b/block/blkdebug.c index b25856c49c..a9b03ff0a2 100644 --- a/block/blkdebug.c +++ b/block/blkdebug.c @@ -821,8 +821,15 @@ 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) { + if (prealloc != PREALLOC_MODE_OFF) { + error_setg(errp, "Unsupported preallocation mode '%s'", + PreallocMode_lookup[prealloc]); + return -ENOTSUP; + } + return bdrv_truncate(bs->file, offset, errp); } diff --git a/block/crypto.c b/block/crypto.c index c561cbad7a..33f690f6d8 100644 --- a/block/crypto.c +++ b/block/crypto.c @@ -361,12 +361,18 @@ 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 = qcrypto_block_get_payload_offset(crypto->block); + if (prealloc != PREALLOC_MODE_OFF) { + error_setg(errp, "Unsupported preallocation mode '%s'", + PreallocMode_lookup[prealloc]); + return -ENOTSUP; + } + offset += payload_offset; return bdrv_truncate(bs->file, offset, errp); diff --git a/block/file-posix.c b/block/file-posix.c index 3927fabf06..4a40976d4c 100644 --- a/block/file-posix.c +++ b/block/file-posix.c @@ -1624,12 +1624,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; struct stat st; int ret; + if (prealloc != PREALLOC_MODE_OFF) { + error_setg(errp, "Unsupported preallocation mode '%s'", + PreallocMode_lookup[prealloc]); + return -ENOTSUP; + } + if (fstat(s->fd, &st)) { ret = -errno; error_setg_errno(errp, -ret, "Failed to fstat() the file"); diff --git a/block/file-win32.c b/block/file-win32.c index ef2910b03f..4706335cff 100644 --- a/block/file-win32.c +++ b/block/file-win32.c @@ -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; diff --git a/block/gluster.c b/block/gluster.c index addceed6eb..bfa4df1c81 100644 --- a/block/gluster.c +++ b/block/gluster.c @@ -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; diff --git a/block/iscsi.c b/block/iscsi.c index 54067e2620..904ef2076b 100644 --- a/block/iscsi.c +++ b/block/iscsi.c @@ -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; diff --git a/block/nfs.c b/block/nfs.c index c3c5de0113..c396ee1dbd 100644 --- a/block/nfs.c +++ b/block/nfs.c @@ -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"); diff --git a/block/qcow2.c b/block/qcow2.c index 52dc6bf3c9..b7c5994f0d 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -3058,12 +3058,19 @@ static coroutine_fn int qcow2_co_pdiscard(BlockDriverState *bs, return ret; } -static int qcow2_truncate(BlockDriverState *bs, int64_t offset, Error **errp) +static int qcow2_truncate(BlockDriverState *bs, int64_t offset, + PreallocMode prealloc, Error **errp) { BDRVQcow2State *s = bs->opaque; int64_t new_l1_size; int ret; + if (prealloc != PREALLOC_MODE_OFF) { + error_setg(errp, "Unsupported preallocation mode '%s'", + PreallocMode_lookup[prealloc]); + return -ENOTSUP; + } + if (offset & 511) { error_setg(errp, "The new size must be a multiple of 512"); return -EINVAL; diff --git a/block/qed.c b/block/qed.c index 385381a78a..8f7e45ca5c 100644 --- a/block/qed.c +++ b/block/qed.c @@ -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"); diff --git a/block/raw-format.c b/block/raw-format.c index a1622c6219..721c9a025b 100644 --- a/block/raw-format.c +++ b/block/raw-format.c @@ -352,10 +352,17 @@ 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; + if (prealloc != PREALLOC_MODE_OFF) { + error_setg(errp, "Unsupported preallocation mode '%s'", + PreallocMode_lookup[prealloc]); + return -ENOTSUP; + } + if (s->has_size) { error_setg(errp, "Cannot resize fixed-size raw disks"); return -ENOTSUP; diff --git a/block/rbd.c b/block/rbd.c index 9da02cdceb..9151d5caa6 100644 --- a/block/rbd.c +++ b/block/rbd.c @@ -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"); diff --git a/block/sheepdog.c b/block/sheepdog.c index 08d7b11e9d..b7b7e6bbe5 100644 --- a/block/sheepdog.c +++ b/block/sheepdog.c @@ -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; } diff --git a/include/block/block_int.h b/include/block/block_int.h index d0cd8a3c58..669a2797fd 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -204,7 +204,8 @@ 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; From 7ea37c30660d4cd6aca21a324fabefe23b89f931 Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Tue, 13 Jun 2017 22:20:53 +0200 Subject: [PATCH 71/85] block: Add PreallocMode to bdrv_truncate() For block drivers that just pass a truncate request to the underlying protocol, we can now pass the preallocation mode instead of aborting if it is not PREALLOC_MODE_OFF. Signed-off-by: Max Reitz Reviewed-by: Stefan Hajnoczi Message-id: 20170613202107.10125-3-mreitz@redhat.com Signed-off-by: Max Reitz --- block.c | 5 +++-- block/blkdebug.c | 8 +------- block/block-backend.c | 2 +- block/crypto.c | 8 +------- block/parallels.c | 11 +++++++---- block/qcow.c | 6 ++++-- block/qcow2-refcount.c | 2 +- block/qcow2.c | 4 ++-- block/raw-format.c | 8 +------- block/vhdx-log.c | 2 +- block/vhdx.c | 3 ++- include/block/block.h | 3 ++- 12 files changed, 26 insertions(+), 36 deletions(-) diff --git a/block.c b/block.c index 37e7b3d30a..d24ae85868 100644 --- a/block.c +++ b/block.c @@ -3411,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; @@ -3434,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, PREALLOC_MODE_OFF, 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); diff --git a/block/blkdebug.c b/block/blkdebug.c index a9b03ff0a2..c19ab28f07 100644 --- a/block/blkdebug.c +++ b/block/blkdebug.c @@ -824,13 +824,7 @@ static int64_t blkdebug_getlength(BlockDriverState *bs) static int blkdebug_truncate(BlockDriverState *bs, int64_t offset, PreallocMode prealloc, Error **errp) { - if (prealloc != PREALLOC_MODE_OFF) { - error_setg(errp, "Unsupported preallocation mode '%s'", - PreallocMode_lookup[prealloc]); - return -ENOTSUP; - } - - return bdrv_truncate(bs->file, offset, errp); + return bdrv_truncate(bs->file, offset, prealloc, errp); } static void blkdebug_refresh_filename(BlockDriverState *bs, QDict *options) diff --git a/block/block-backend.c b/block/block-backend.c index 0df3457a09..3c1b75648a 100644 --- a/block/block-backend.c +++ b/block/block-backend.c @@ -1780,7 +1780,7 @@ int blk_truncate(BlockBackend *blk, int64_t offset, Error **errp) return -ENOMEDIUM; } - return bdrv_truncate(blk->root, offset, errp); + return bdrv_truncate(blk->root, offset, PREALLOC_MODE_OFF, errp); } static void blk_pdiscard_entry(void *opaque) diff --git a/block/crypto.c b/block/crypto.c index 33f690f6d8..58ef6f2f52 100644 --- a/block/crypto.c +++ b/block/crypto.c @@ -367,15 +367,9 @@ static int block_crypto_truncate(BlockDriverState *bs, int64_t offset, size_t payload_offset = qcrypto_block_get_payload_offset(crypto->block); - if (prealloc != PREALLOC_MODE_OFF) { - error_setg(errp, "Unsupported preallocation mode '%s'", - PreallocMode_lookup[prealloc]); - return -ENOTSUP; - } - 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) diff --git a/block/parallels.c b/block/parallels.c index 8be46a7d48..5a38998cbb 100644 --- a/block/parallels.c +++ b/block/parallels.c @@ -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++; @@ -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); diff --git a/block/qcow.c b/block/qcow.c index 2002c169be..10c96b86aa 100644 --- a/block/qcow.c +++ b/block/qcow.c @@ -443,7 +443,8 @@ 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 && @@ -923,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; diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c index ceb08bc16f..e82e155208 100644 --- a/block/qcow2-refcount.c +++ b/block/qcow2-refcount.c @@ -1732,7 +1732,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; diff --git a/block/qcow2.c b/block/qcow2.c index b7c5994f0d..7391b497f7 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -3133,7 +3133,7 @@ qcow2_co_pwritev_compressed(BlockDriverState *bs, uint64_t offset, /* align end of file to a sector boundary to ease reading with sector based I/Os */ cluster_offset = bdrv_getlength(bs->file->bs); - return bdrv_truncate(bs->file, cluster_offset, NULL); + return bdrv_truncate(bs->file, cluster_offset, PREALLOC_MODE_OFF, NULL); } buf = qemu_blockalign(bs, s->cluster_size); @@ -3349,7 +3349,7 @@ static int make_completely_empty(BlockDriverState *bs) } ret = bdrv_truncate(bs->file, (3 + l1_clusters) * s->cluster_size, - &local_err); + PREALLOC_MODE_OFF, &local_err); if (ret < 0) { error_report_err(local_err); goto fail; diff --git a/block/raw-format.c b/block/raw-format.c index 721c9a025b..142649ed56 100644 --- a/block/raw-format.c +++ b/block/raw-format.c @@ -357,12 +357,6 @@ static int raw_truncate(BlockDriverState *bs, int64_t offset, { BDRVRawState *s = bs->opaque; - if (prealloc != PREALLOC_MODE_OFF) { - error_setg(errp, "Unsupported preallocation mode '%s'", - PreallocMode_lookup[prealloc]); - return -ENOTSUP; - } - if (s->has_size) { error_setg(errp, "Cannot resize fixed-size raw disks"); return -ENOTSUP; @@ -375,7 +369,7 @@ static int raw_truncate(BlockDriverState *bs, int64_t offset, 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) diff --git a/block/vhdx-log.c b/block/vhdx-log.c index 3f4c2aa095..01278f3fc9 100644 --- a/block/vhdx-log.c +++ b/block/vhdx-log.c @@ -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); diff --git a/block/vhdx.c b/block/vhdx.c index 8b270b57c9..85c476a152 100644 --- a/block/vhdx.c +++ b/block/vhdx.c @@ -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); } /* diff --git a/include/block/block.h b/include/block/block.h index 96edc85129..b3e2674845 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -302,7 +302,8 @@ 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); From 3a691c50f10344b052ad70a4d0ed935276ccca3c Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Tue, 13 Jun 2017 22:20:54 +0200 Subject: [PATCH 72/85] block: Add PreallocMode to blk_truncate() blk_truncate() itself will pass that value to bdrv_truncate(), and all callers of blk_truncate() just set the parameter to PREALLOC_MODE_OFF for now. Signed-off-by: Max Reitz Reviewed-by: Stefan Hajnoczi Message-id: 20170613202107.10125-4-mreitz@redhat.com Signed-off-by: Max Reitz --- block/block-backend.c | 5 +++-- block/commit.c | 4 ++-- block/mirror.c | 3 ++- block/parallels.c | 2 +- block/qcow.c | 2 +- block/qcow2.c | 4 ++-- block/qed.c | 2 +- block/vdi.c | 3 ++- block/vhdx.c | 5 +++-- block/vmdk.c | 7 ++++--- block/vpc.c | 2 +- blockdev.c | 2 +- include/sysemu/block-backend.h | 3 ++- qemu-img.c | 2 +- qemu-io-cmds.c | 2 +- 15 files changed, 27 insertions(+), 21 deletions(-) diff --git a/block/block-backend.c b/block/block-backend.c index 3c1b75648a..fe3542b3f8 100644 --- a/block/block-backend.c +++ b/block/block-backend.c @@ -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, PREALLOC_MODE_OFF, errp); + return bdrv_truncate(blk->root, offset, prealloc, errp); } static void blk_pdiscard_entry(void *opaque) diff --git a/block/commit.c b/block/commit.c index 774a8a599c..13143608f8 100644 --- a/block/commit.c +++ b/block/commit.c @@ -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; diff --git a/block/mirror.c b/block/mirror.c index eaf0fe7858..8583b764a0 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -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; } diff --git a/block/parallels.c b/block/parallels.c index 5a38998cbb..5bbdfabb7a 100644 --- a/block/parallels.c +++ b/block/parallels.c @@ -508,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; } diff --git a/block/qcow.c b/block/qcow.c index 10c96b86aa..66827d6f24 100644 --- a/block/qcow.c +++ b/block/qcow.c @@ -813,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; } diff --git a/block/qcow2.c b/block/qcow2.c index 7391b497f7..0f44780465 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -2802,7 +2802,7 @@ static int qcow2_create2(const char *filename, int64_t total_size, } /* Okay, now that we have a valid image, let's give it the right size */ - ret = blk_truncate(blk, total_size, errp); + ret = blk_truncate(blk, total_size, PREALLOC_MODE_OFF, errp); if (ret < 0) { error_prepend(errp, "Could not resize image: "); goto out; @@ -3995,7 +3995,7 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts, return ret; } - ret = blk_truncate(blk, new_size, &local_err); + ret = blk_truncate(blk, new_size, PREALLOC_MODE_OFF, &local_err); blk_unref(blk); if (ret < 0) { error_report_err(local_err); diff --git a/block/qed.c b/block/qed.c index 8f7e45ca5c..86cad2188c 100644 --- a/block/qed.c +++ b/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; } diff --git a/block/vdi.c b/block/vdi.c index 79af47763b..2b6e8fa1ed 100644 --- a/block/vdi.c +++ b/block/vdi.c @@ -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; diff --git a/block/vhdx.c b/block/vhdx.c index 85c476a152..a9cecd2773 100644 --- a/block/vhdx.c +++ b/block/vhdx.c @@ -1608,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; } diff --git a/block/vmdk.c b/block/vmdk.c index 55581b03fe..24d71b5982 100644 --- a/block/vmdk.c +++ b/block/vmdk.c @@ -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) { diff --git a/block/vpc.c b/block/vpc.c index b313c68148..9a6f8173a5 100644 --- a/block/vpc.c +++ b/block/vpc.c @@ -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; } diff --git a/blockdev.c b/blockdev.c index 124c23000e..9c6dd270b7 100644 --- a/blockdev.c +++ b/blockdev.c @@ -2958,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: diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h index 1e05281fff..d9ea0cdb0f 100644 --- a/include/sysemu/block-backend.h +++ b/include/sysemu/block-backend.h @@ -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); diff --git a/qemu-img.c b/qemu-img.c index 930ae88a0d..1b741956bc 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -3537,7 +3537,7 @@ static int img_resize(int argc, char **argv) goto out; } - ret = blk_truncate(blk, total_size, &err); + ret = blk_truncate(blk, total_size, PREALLOC_MODE_OFF, &err); if (!ret) { qprintf(quiet, "Image resized.\n"); } else { diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c index f4fdf2dcce..3eb42c6728 100644 --- a/qemu-io-cmds.c +++ b/qemu-io-cmds.c @@ -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; From dc5f690b97ccdffa79fe7169bb26b0ebf06688bf Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Tue, 13 Jun 2017 22:20:55 +0200 Subject: [PATCH 73/85] qemu-img: Expose PreallocMode for resizing Add a --preallocation command line option to qemu-img resize which can be used to set the PreallocMode parameter of blk_truncate(). While touching this code, fix the fact that we did not handle errors returned by blk_getlength(). Signed-off-by: Max Reitz Message-id: 20170613202107.10125-5-mreitz@redhat.com Reviewed-by: Stefan Hajnoczi Signed-off-by: Max Reitz --- qemu-img.c | 33 ++++++++++++++++++++++++++++++--- qemu-img.texi | 7 ++++++- 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/qemu-img.c b/qemu-img.c index 1b741956bc..28022145d5 100644 --- a/qemu-img.c +++ b/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" @@ -62,6 +63,7 @@ enum { OPTION_NO_DRAIN = 262, OPTION_TARGET_IMAGE_OPTS = 263, OPTION_SIZE = 264, + OPTION_PREALLOCATION = 265, }; typedef enum OutputFormat { @@ -3408,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 = { @@ -3444,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", @@ -3478,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) { @@ -3526,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; } @@ -3537,7 +3558,13 @@ static int img_resize(int argc, char **argv) goto out; } - ret = blk_truncate(blk, total_size, PREALLOC_MODE_OFF, &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 { diff --git a/qemu-img.texi b/qemu-img.texi index a2f45199d2..f11f6036ad 100644 --- a/qemu-img.texi +++ b/qemu-img.texi @@ -529,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}. @@ -541,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 From 7dacd8bd3d1f7eeb1850d5ad8e1898e6d314889f Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Tue, 13 Jun 2017 22:20:56 +0200 Subject: [PATCH 74/85] block/file-posix: Small fixes in raw_create() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Variables should be declared at the start of a block, and if a certain parameter value is not supported it may be better to return -ENOTSUP instead of -EINVAL. Signed-off-by: Max Reitz Reviewed-by: Stefan Hajnoczi Reviewed-by: Philippe Mathieu-Daudé Message-id: 20170613202107.10125-6-mreitz@redhat.com Signed-off-by: Max Reitz --- block/file-posix.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/block/file-posix.c b/block/file-posix.c index 4a40976d4c..3388def9b1 100644 --- a/block/file-posix.c +++ b/block/file-posix.c @@ -1910,6 +1910,8 @@ static int raw_create(const char *filename, QemuOpts *opts, Error **errp) #endif case PREALLOC_MODE_FULL: { + int64_t num = 0, left = total_size; + /* * Knowing the final size from the beginning could allow the file * system driver to do less allocations and possibly avoid @@ -1921,7 +1923,6 @@ static int raw_create(const char *filename, QemuOpts *opts, Error **errp) goto out_close; } - int64_t num = 0, left = total_size; buf = g_malloc0(65536); while (left > 0) { @@ -1953,7 +1954,7 @@ static int raw_create(const char *filename, QemuOpts *opts, Error **errp) } break; default: - result = -EINVAL; + result = -ENOTSUP; error_setg(errp, "Unsupported preallocation mode: %s", PreallocMode_lookup[prealloc]); break; From 9f63b07ee7feefd5f5a1175614b6948264e9d7e0 Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Tue, 13 Jun 2017 22:20:57 +0200 Subject: [PATCH 75/85] block/file-posix: Extract raw_regular_truncate() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This functionality is part of raw_create() which we will be able to reuse nicely in raw_truncate(). Signed-off-by: Max Reitz Reviewed-by: Stefan Hajnoczi Reviewed-by: Philippe Mathieu-Daudé Message-id: 20170613202107.10125-7-mreitz@redhat.com Signed-off-by: Max Reitz --- block/file-posix.c | 144 ++++++++++++++++++++++++--------------------- 1 file changed, 78 insertions(+), 66 deletions(-) diff --git a/block/file-posix.c b/block/file-posix.c index 3388def9b1..deefd6efac 100644 --- a/block/file-posix.c +++ b/block/file-posix.c @@ -1624,6 +1624,81 @@ static void raw_close(BlockDriverState *bs) } } +static int raw_regular_truncate(int fd, int64_t offset, PreallocMode prealloc, + Error **errp) +{ + int result = 0; + char *buf; + + 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, offset); + if (result != 0) { + /* posix_fallocate() doesn't set errno. */ + error_setg_errno(errp, -result, + "Could not preallocate data for the new file"); + } + return result; +#endif + case PREALLOC_MODE_FULL: + { + int64_t num = 0, left = offset; + + /* + * 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"); + return result; + } + + 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); + return result; + } + 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; + } +} + static int raw_truncate(BlockDriverState *bs, int64_t offset, PreallocMode prealloc, Error **errp) { @@ -1892,72 +1967,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: - { - int64_t num = 0, left = total_size; - - /* - * 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; - } - - 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 = -ENOTSUP; - 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: From d0bc9e5d5e86d5dd566e2d967af8476cee351c93 Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Tue, 13 Jun 2017 22:20:58 +0200 Subject: [PATCH 76/85] block/file-posix: Generalize raw_regular_truncate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, raw_regular_truncate() is intended for setting the size of a newly created file. However, we also want to use it for truncating an existing file in which case only the newly added space (when growing) should be preallocated. This also means that if resizing failed, we should try to restore the original file size. This is important when using preallocation. Signed-off-by: Max Reitz Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Stefan Hajnoczi Message-id: 20170613202107.10125-8-mreitz@redhat.com Signed-off-by: Max Reitz --- block/file-posix.c | 61 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 50 insertions(+), 11 deletions(-) diff --git a/block/file-posix.c b/block/file-posix.c index deefd6efac..59154ea936 100644 --- a/block/file-posix.c +++ b/block/file-posix.c @@ -1624,11 +1624,31 @@ static void raw_close(BlockDriverState *bs) } } +/** + * 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; - char *buf; + 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 @@ -1638,17 +1658,17 @@ static int raw_regular_truncate(int fd, int64_t offset, PreallocMode prealloc, * 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, offset); + 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 data for the new file"); + "Could not preallocate new data"); } - return result; + goto out; #endif case PREALLOC_MODE_FULL: { - int64_t num = 0, left = offset; + int64_t num = 0, left = offset - current_length; /* * Knowing the final size from the beginning could allow the file @@ -1658,19 +1678,27 @@ static int raw_regular_truncate(int fd, int64_t offset, PreallocMode prealloc, if (ftruncate(fd, offset) != 0) { result = -errno; error_setg_errno(errp, -result, "Could not resize file"); - return result; + 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 to the new file"); - break; + "Could not write zeros for preallocation"); + goto out; } left -= result; } @@ -1679,11 +1707,11 @@ static int raw_regular_truncate(int fd, int64_t offset, PreallocMode prealloc, if (result < 0) { result = -errno; error_setg_errno(errp, -result, - "Could not flush new file to disk"); + "Could not flush file to disk"); + goto out; } } - g_free(buf); - return result; + goto out; } case PREALLOC_MODE_OFF: if (ftruncate(fd, offset) != 0) { @@ -1697,6 +1725,17 @@ static int raw_regular_truncate(int fd, int64_t offset, PreallocMode prealloc, 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, From 35d72602ec5709b5078ff0e6361eee57fb652f98 Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Tue, 13 Jun 2017 22:20:59 +0200 Subject: [PATCH 77/85] block/file-posix: Preallocation for truncate By using raw_regular_truncate() in raw_truncate(), we can now easily support preallocation. Signed-off-by: Max Reitz Reviewed-by: Stefan Hajnoczi Message-id: 20170613202107.10125-9-mreitz@redhat.com Signed-off-by: Max Reitz --- block/file-posix.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/block/file-posix.c b/block/file-posix.c index 59154ea936..cfbb236f6f 100644 --- a/block/file-posix.c +++ b/block/file-posix.c @@ -1745,12 +1745,6 @@ static int raw_truncate(BlockDriverState *bs, int64_t offset, struct stat st; int ret; - if (prealloc != PREALLOC_MODE_OFF) { - error_setg(errp, "Unsupported preallocation mode '%s'", - PreallocMode_lookup[prealloc]); - return -ENOTSUP; - } - if (fstat(s->fd, &st)) { ret = -errno; error_setg_errno(errp, -ret, "Failed to fstat() the file"); @@ -1758,12 +1752,16 @@ static int raw_truncate(BlockDriverState *bs, int64_t offset, } 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; From 7bc45dc17265772abe5dd1d4649c7bb42e1c6df1 Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Tue, 13 Jun 2017 22:21:00 +0200 Subject: [PATCH 78/85] block/qcow2: Generalize preallocate() This patch adds two new parameters to the preallocate() function so we will be able to use it not just for preallocating a new image but also for preallocated image growth. The offset parameter allows the caller to specify a virtual offset from which to start preallocating. For newly created images this is always 0, but for preallocating growth this will be the old image length. The new_length parameter specifies the supposed new length of the image (basically the "end offset" for preallocation). During image truncation, bdrv_getlength() will return the old image length so we cannot rely on its return value then. Signed-off-by: Max Reitz Reviewed-by: Eric Blake Reviewed-by: Stefan Hajnoczi Message-id: 20170613202107.10125-10-mreitz@redhat.com Signed-off-by: Max Reitz --- block/qcow2.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/block/qcow2.c b/block/qcow2.c index 0f44780465..1ee8452d80 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -2476,17 +2476,24 @@ static int qcow2_set_up_encryption(BlockDriverState *bs, const char *encryptfmt, } -static int preallocate(BlockDriverState *bs) +/** + * Preallocates metadata structures for data clusters between @offset (in the + * guest disk) and @new_length (which is thus generally the new guest disk + * size). + * + * Returns: 0 on success, -errno on failure. + */ +static int preallocate(BlockDriverState *bs, + uint64_t offset, uint64_t new_length) { uint64_t bytes; - uint64_t offset; uint64_t host_offset = 0; unsigned int cur_bytes; int ret; QCowL2Meta *meta; - bytes = bdrv_getlength(bs); - offset = 0; + assert(offset <= new_length); + bytes = new_length - offset; while (bytes) { cur_bytes = MIN(bytes, INT_MAX); @@ -2830,7 +2837,7 @@ static int qcow2_create2(const char *filename, int64_t total_size, if (prealloc != PREALLOC_MODE_OFF) { BDRVQcow2State *s = blk_bs(blk)->opaque; qemu_co_mutex_lock(&s->lock); - ret = preallocate(blk_bs(blk)); + ret = preallocate(blk_bs(blk), 0, total_size); qemu_co_mutex_unlock(&s->lock); if (ret < 0) { error_setg_errno(errp, -ret, "Could not preallocate metadata"); From 652fecd0058de7d90609c347bfdbeff76ef817a6 Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Tue, 13 Jun 2017 22:21:01 +0200 Subject: [PATCH 79/85] block/qcow2: Lock s->lock in preallocate() preallocate() is and will be called only from places that do not otherwise need to lock s->lock: Currently that is qcow2_create2(), as of a future patch it will be called from qcow2_truncate(), too. It therefore makes sense to move locking that mutex into preallocate() itself. Signed-off-by: Max Reitz Reviewed-by: Eric Blake Reviewed-by: Stefan Hajnoczi Message-id: 20170613202107.10125-11-mreitz@redhat.com Signed-off-by: Max Reitz --- block/qcow2.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/block/qcow2.c b/block/qcow2.c index 1ee8452d80..d3fb2f3f79 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -2486,12 +2486,17 @@ static int qcow2_set_up_encryption(BlockDriverState *bs, const char *encryptfmt, static int preallocate(BlockDriverState *bs, uint64_t offset, uint64_t new_length) { + BDRVQcow2State *s = bs->opaque; uint64_t bytes; uint64_t host_offset = 0; unsigned int cur_bytes; int ret; QCowL2Meta *meta; + if (qemu_in_coroutine()) { + qemu_co_mutex_lock(&s->lock); + } + assert(offset <= new_length); bytes = new_length - offset; @@ -2500,7 +2505,7 @@ static int preallocate(BlockDriverState *bs, ret = qcow2_alloc_cluster_offset(bs, offset, &cur_bytes, &host_offset, &meta); if (ret < 0) { - return ret; + goto done; } while (meta) { @@ -2510,7 +2515,7 @@ static int preallocate(BlockDriverState *bs, if (ret < 0) { qcow2_free_any_clusters(bs, meta->alloc_offset, meta->nb_clusters, QCOW2_DISCARD_NEVER); - return ret; + goto done; } /* There are no dependent requests, but we need to remove our @@ -2537,11 +2542,17 @@ static int preallocate(BlockDriverState *bs, ret = bdrv_pwrite(bs->file, (host_offset + cur_bytes) - 1, &data, 1); if (ret < 0) { - return ret; + goto done; } } - return 0; + ret = 0; + +done: + if (qemu_in_coroutine()) { + qemu_co_mutex_unlock(&s->lock); + } + return ret; } /* qcow2_refcount_metadata_size: @@ -2835,10 +2846,7 @@ static int qcow2_create2(const char *filename, int64_t total_size, /* And if we're supposed to preallocate metadata, do that now */ if (prealloc != PREALLOC_MODE_OFF) { - BDRVQcow2State *s = blk_bs(blk)->opaque; - qemu_co_mutex_lock(&s->lock); ret = preallocate(blk_bs(blk), 0, total_size); - qemu_co_mutex_unlock(&s->lock); if (ret < 0) { error_setg_errno(errp, -ret, "Could not preallocate metadata"); goto out; From 95b98f343b054e100a905181cd140c653c80cbad Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Tue, 13 Jun 2017 22:21:02 +0200 Subject: [PATCH 80/85] block/qcow2: Metadata preallocation for truncate We can support PREALLOC_MODE_METADATA by invoking preallocate() in qcow2_truncate(). Signed-off-by: Max Reitz Message-id: 20170613202107.10125-12-mreitz@redhat.com Reviewed-by: Stefan Hajnoczi Signed-off-by: Max Reitz --- block/qcow2.c | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/block/qcow2.c b/block/qcow2.c index d3fb2f3f79..47537d0a3f 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -3077,10 +3077,11 @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset, PreallocMode prealloc, Error **errp) { BDRVQcow2State *s = bs->opaque; + uint64_t old_length; int64_t new_l1_size; int ret; - if (prealloc != PREALLOC_MODE_OFF) { + if (prealloc != PREALLOC_MODE_OFF && prealloc != PREALLOC_MODE_METADATA) { error_setg(errp, "Unsupported preallocation mode '%s'", PreallocMode_lookup[prealloc]); return -ENOTSUP; @@ -3104,8 +3105,10 @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset, return -ENOTSUP; } + old_length = bs->total_sectors * 512; + /* shrinking is currently not supported */ - if (offset < bs->total_sectors * 512) { + if (offset < old_length) { error_setg(errp, "qcow2 doesn't support shrinking images yet"); return -ENOTSUP; } @@ -3117,6 +3120,32 @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset, return ret; } + switch (prealloc) { + case PREALLOC_MODE_OFF: + break; + + case PREALLOC_MODE_METADATA: + ret = preallocate(bs, old_length, offset); + if (ret < 0) { + error_setg_errno(errp, -ret, "Preallocation failed"); + return ret; + } + break; + + default: + g_assert_not_reached(); + } + + if (prealloc != PREALLOC_MODE_OFF) { + /* Flush metadata before actually changing the image size */ + ret = bdrv_flush(bs); + if (ret < 0) { + error_setg_errno(errp, -ret, + "Failed to flush the preallocated area to disk"); + return ret; + } + } + /* write updated header.size */ offset = cpu_to_be64(offset); ret = bdrv_pwrite_sync(bs->file, offsetof(QCowHeader, size), From 12cc30a8cbdbb4c9c90cbffb970dfa679a1e3212 Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Tue, 13 Jun 2017 22:21:03 +0200 Subject: [PATCH 81/85] block/qcow2: Add qcow2_refcount_area() This function creates a collection of self-describing refcount structures (including a new refcount table) at the end of a qcow2 image file. Optionally, these structures can also describe a number of additional clusters beyond themselves; this will be important for preallocated truncation, which will place the data clusters and L2 tables there. For now, we can use this function to replace the part of alloc_refcount_block() that grows the refcount table (from which it is actually derived). Signed-off-by: Max Reitz Reviewed-by: Stefan Hajnoczi Message-id: 20170613202107.10125-13-mreitz@redhat.com Signed-off-by: Max Reitz --- block/qcow2-refcount.c | 275 +++++++++++++++++++++++++------------ block/qcow2.c | 20 ++- block/qcow2.h | 4 + tests/qemu-iotests/044.out | 2 +- 4 files changed, 208 insertions(+), 93 deletions(-) diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c index e82e155208..082b5de4cd 100644 --- a/block/qcow2-refcount.c +++ b/block/qcow2-refcount.c @@ -34,6 +34,10 @@ static int64_t alloc_clusters_noref(BlockDriverState *bs, uint64_t size); static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs, int64_t offset, int64_t length, uint64_t addend, bool decrease, enum qcow2_discard_type type); +static 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); static uint64_t get_refcount_ro0(const void *refcount_array, uint64_t index); static uint64_t get_refcount_ro1(const void *refcount_array, uint64_t index); @@ -281,25 +285,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 +306,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); @@ -490,74 +475,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_block: + 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. + */ +static 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 +677,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 +696,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 +713,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; } diff --git a/block/qcow2.c b/block/qcow2.c index 47537d0a3f..46edea8dec 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -2559,12 +2559,14 @@ done: * @clusters: number of clusters to refcount (including data and L1/L2 tables) * @cluster_size: size of a cluster, in bytes * @refcount_order: refcount bits power-of-2 exponent + * @generous_increase: allow for the refcount table to be 1.5x as large as it + * needs to be * * Returns: Number of bytes required for refcount blocks and table metadata. */ -static int64_t qcow2_refcount_metadata_size(int64_t clusters, - size_t cluster_size, - int refcount_order) +int64_t qcow2_refcount_metadata_size(int64_t clusters, size_t cluster_size, + int refcount_order, bool generous_increase, + uint64_t *refblock_count) { /* * Every host cluster is reference-counted, including metadata (even @@ -2587,8 +2589,18 @@ static int64_t qcow2_refcount_metadata_size(int64_t clusters, blocks = DIV_ROUND_UP(clusters + table + blocks, refcounts_per_block); table = DIV_ROUND_UP(blocks, blocks_per_table_cluster); n = clusters + blocks + table; + + if (n == last && generous_increase) { + clusters += DIV_ROUND_UP(table, 2); + n = 0; /* force another loop */ + generous_increase = false; + } } while (n != last); + if (refblock_count) { + *refblock_count = blocks; + } + return (blocks + table) * cluster_size; } @@ -2625,7 +2637,7 @@ static int64_t qcow2_calc_prealloc_size(int64_t total_size, /* total size of refcount table and blocks */ meta_size += qcow2_refcount_metadata_size( (meta_size + aligned_total_size) / cluster_size, - cluster_size, refcount_order); + cluster_size, refcount_order, false, NULL); return meta_size + aligned_total_size; } diff --git a/block/qcow2.h b/block/qcow2.h index 2df05ac8dd..3854080725 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -525,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); diff --git a/tests/qemu-iotests/044.out b/tests/qemu-iotests/044.out index 4789a5310e..703cf3dee1 100644 --- a/tests/qemu-iotests/044.out +++ b/tests/qemu-iotests/044.out @@ -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 From 60c48a29b75f3e1276bb046186476674bbc74de9 Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Tue, 13 Jun 2017 22:21:04 +0200 Subject: [PATCH 82/85] block/qcow2: Rename "fail_block" to just "fail" Now alloc_refcount_block() only contains a single fail label, so it makes more sense to just name it "fail" instead of "fail_block". Signed-off-by: Max Reitz Reviewed-by: Stefan Hajnoczi Message-id: 20170613202107.10125-14-mreitz@redhat.com Signed-off-by: Max Reitz --- block/qcow2-refcount.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c index 082b5de4cd..1aca6455f7 100644 --- a/block/qcow2-refcount.c +++ b/block/qcow2-refcount.c @@ -381,7 +381,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); @@ -396,12 +396,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, @@ -409,7 +409,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); @@ -420,7 +420,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 */ @@ -431,7 +431,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; @@ -495,7 +495,7 @@ static int alloc_refcount_block(BlockDriverState *bs, * allocated metadata. Make the caller search some new space. */ return -EAGAIN; -fail_block: +fail: if (*refcount_block != NULL) { qcow2_cache_put(bs, s->refcount_block_cache, refcount_block); } From 772d1f973f87269f6a4a4ea4b880680f3779bbdf Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Tue, 13 Jun 2017 22:21:05 +0200 Subject: [PATCH 83/85] block/qcow2: falloc/full preallocating growth Implement the preallocation modes falloc and full for growing qcow2 images. Signed-off-by: Max Reitz Message-id: 20170613202107.10125-15-mreitz@redhat.com Reviewed-by: Stefan Hajnoczi Signed-off-by: Max Reitz --- block/qcow2-refcount.c | 12 ++--- block/qcow2.c | 100 ++++++++++++++++++++++++++++++++++++++++- block/qcow2.h | 5 +++ 3 files changed, 108 insertions(+), 9 deletions(-) diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c index 1aca6455f7..c9b0dcb4f3 100644 --- a/block/qcow2-refcount.c +++ b/block/qcow2-refcount.c @@ -34,10 +34,6 @@ static int64_t alloc_clusters_noref(BlockDriverState *bs, uint64_t size); static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs, int64_t offset, int64_t length, uint64_t addend, bool decrease, enum qcow2_discard_type type); -static 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); static uint64_t get_refcount_ro0(const void *refcount_array, uint64_t index); static uint64_t get_refcount_ro1(const void *refcount_array, uint64_t index); @@ -517,10 +513,10 @@ fail: * Returns: The offset after the new refcount structures (i.e. where the * @additional_clusters may be placed) on success, -errno on error. */ -static 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) +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; diff --git a/block/qcow2.c b/block/qcow2.c index 46edea8dec..c144ea5620 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -3093,7 +3093,9 @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset, int64_t new_l1_size; int ret; - if (prealloc != PREALLOC_MODE_OFF && prealloc != PREALLOC_MODE_METADATA) { + if (prealloc != PREALLOC_MODE_OFF && prealloc != PREALLOC_MODE_METADATA && + prealloc != PREALLOC_MODE_FALLOC && prealloc != PREALLOC_MODE_FULL) + { error_setg(errp, "Unsupported preallocation mode '%s'", PreallocMode_lookup[prealloc]); return -ENOTSUP; @@ -3144,6 +3146,102 @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset, } break; + case PREALLOC_MODE_FALLOC: + case PREALLOC_MODE_FULL: + { + int64_t allocation_start, host_offset, guest_offset; + int64_t clusters_allocated; + int64_t old_file_size, new_file_size; + uint64_t nb_new_data_clusters, nb_new_l2_tables; + + old_file_size = bdrv_getlength(bs->file->bs); + if (old_file_size < 0) { + error_setg_errno(errp, -old_file_size, + "Failed to inquire current file length"); + return ret; + } + + nb_new_data_clusters = DIV_ROUND_UP(offset - old_length, + s->cluster_size); + + /* This is an overestimation; we will not actually allocate space for + * these in the file but just make sure the new refcount structures are + * able to cover them so we will not have to allocate new refblocks + * while entering the data blocks in the potentially new L2 tables. + * (We do not actually care where the L2 tables are placed. Maybe they + * are already allocated or they can be placed somewhere before + * @old_file_size. It does not matter because they will be fully + * allocated automatically, so they do not need to be covered by the + * preallocation. All that matters is that we will not have to allocate + * new refcount structures for them.) */ + nb_new_l2_tables = DIV_ROUND_UP(nb_new_data_clusters, + s->cluster_size / sizeof(uint64_t)); + /* The cluster range may not be aligned to L2 boundaries, so add one L2 + * table for a potential head/tail */ + nb_new_l2_tables++; + + allocation_start = qcow2_refcount_area(bs, old_file_size, + nb_new_data_clusters + + nb_new_l2_tables, + true, 0, 0); + if (allocation_start < 0) { + error_setg_errno(errp, -allocation_start, + "Failed to resize refcount structures"); + return -allocation_start; + } + + clusters_allocated = qcow2_alloc_clusters_at(bs, allocation_start, + nb_new_data_clusters); + if (clusters_allocated < 0) { + error_setg_errno(errp, -clusters_allocated, + "Failed to allocate data clusters"); + return -clusters_allocated; + } + + assert(clusters_allocated == nb_new_data_clusters); + + /* Allocate the data area */ + new_file_size = allocation_start + + nb_new_data_clusters * s->cluster_size; + ret = bdrv_truncate(bs->file, new_file_size, prealloc, errp); + if (ret < 0) { + error_prepend(errp, "Failed to resize underlying file: "); + qcow2_free_clusters(bs, allocation_start, + nb_new_data_clusters * s->cluster_size, + QCOW2_DISCARD_OTHER); + return ret; + } + + /* Create the necessary L2 entries */ + host_offset = allocation_start; + guest_offset = old_length; + while (nb_new_data_clusters) { + int64_t guest_cluster = guest_offset >> s->cluster_bits; + int64_t nb_clusters = MIN(nb_new_data_clusters, + s->l2_size - guest_cluster % s->l2_size); + QCowL2Meta allocation = { + .offset = guest_offset, + .alloc_offset = host_offset, + .nb_clusters = nb_clusters, + }; + qemu_co_queue_init(&allocation.dependent_requests); + + ret = qcow2_alloc_cluster_link_l2(bs, &allocation); + if (ret < 0) { + error_setg_errno(errp, -ret, "Failed to update L2 tables"); + qcow2_free_clusters(bs, host_offset, + nb_new_data_clusters * s->cluster_size, + QCOW2_DISCARD_OTHER); + return ret; + } + + guest_offset += nb_clusters * s->cluster_size; + host_offset += nb_clusters * s->cluster_size; + nb_new_data_clusters -= nb_clusters; + } + break; + } + default: g_assert_not_reached(); } diff --git a/block/qcow2.h b/block/qcow2.h index 3854080725..96a8d43c17 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -549,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); From a2c7e082123a17dc1e31262ad136a3b45b3b0cb6 Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Tue, 13 Jun 2017 22:21:06 +0200 Subject: [PATCH 84/85] iotests: Add preallocated resize test for raw Signed-off-by: Max Reitz Reviewed-by: Stefan Hajnoczi Message-id: 20170613202107.10125-16-mreitz@redhat.com Signed-off-by: Max Reitz --- tests/qemu-iotests/106 | 92 ++++++++++++++++++++++++++++++++++++++ tests/qemu-iotests/106.out | 50 +++++++++++++++++++++ tests/qemu-iotests/group | 1 + 3 files changed, 143 insertions(+) create mode 100755 tests/qemu-iotests/106 create mode 100644 tests/qemu-iotests/106.out diff --git a/tests/qemu-iotests/106 b/tests/qemu-iotests/106 new file mode 100755 index 0000000000..32649578fb --- /dev/null +++ b/tests/qemu-iotests/106 @@ -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 . +# + +# 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 diff --git a/tests/qemu-iotests/106.out b/tests/qemu-iotests/106.out new file mode 100644 index 0000000000..0a42312301 --- /dev/null +++ b/tests/qemu-iotests/106.out @@ -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 diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group index 8f883f7559..de1409105b 100644 --- a/tests/qemu-iotests/group +++ b/tests/qemu-iotests/group @@ -112,6 +112,7 @@ 103 rw auto quick 104 rw auto 105 rw auto quick +106 rw auto quick 107 rw auto quick 108 rw auto quick 109 rw auto From ced14843229cd42c282f0ee4b43bbcdc324c923a Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Tue, 13 Jun 2017 22:21:07 +0200 Subject: [PATCH 85/85] iotests: Add preallocated growth test for qcow2 Signed-off-by: Max Reitz Reviewed-by: Stefan Hajnoczi Message-id: 20170613202107.10125-17-mreitz@redhat.com Signed-off-by: Max Reitz --- tests/qemu-iotests/125 | 130 +++++++++++++ tests/qemu-iotests/125.out | 386 +++++++++++++++++++++++++++++++++++++ tests/qemu-iotests/group | 1 + 3 files changed, 517 insertions(+) create mode 100755 tests/qemu-iotests/125 create mode 100644 tests/qemu-iotests/125.out diff --git a/tests/qemu-iotests/125 b/tests/qemu-iotests/125 new file mode 100755 index 0000000000..9424313e82 --- /dev/null +++ b/tests/qemu-iotests/125 @@ -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 . +# + +# 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 diff --git a/tests/qemu-iotests/125.out b/tests/qemu-iotests/125.out new file mode 100644 index 0000000000..3f4d6e31a6 --- /dev/null +++ b/tests/qemu-iotests/125.out @@ -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 diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group index de1409105b..2aba585287 100644 --- a/tests/qemu-iotests/group +++ b/tests/qemu-iotests/group @@ -131,6 +131,7 @@ 122 rw auto 123 rw auto quick 124 rw auto backing +125 rw auto 126 rw auto backing 128 rw auto quick 129 rw auto quick