[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-block] [PATCH 07/11] qcow2-threads: add encryption
From: |
Vladimir Sementsov-Ogievskiy |
Subject: |
[Qemu-block] [PATCH 07/11] qcow2-threads: add encryption |
Date: |
Fri, 23 Nov 2018 19:55:07 +0300 |
Add thread-based encrypt/decrypt. QCrypto don't support parallel
operations with one block, so we need QCryptoBlock for each thread.
Signed-off-by: Vladimir Sementsov-Ogievskiy <address@hidden>
---
block/qcow2.h | 12 +++++++++
block/qcow2-threads.c | 62 +++++++++++++++++++++++++++++++++++++++++++
block/qcow2.c | 57 ++++++++++++++++++++++++++++++++-------
3 files changed, 122 insertions(+), 9 deletions(-)
diff --git a/block/qcow2.h b/block/qcow2.h
index 7bef0393ce..351ad8d3e7 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -260,6 +260,12 @@ typedef struct Qcow2BitmapHeaderExt {
#define QCOW2_MAX_THREADS 4
typedef struct Qcow2PerThreadData {
bool in_use;
+
+ /* QCryptoBlock doesn't support parallel operations in threads, so we can't
+ * use BDRVQcow2State.crypto and instead we need separate crypto block for
+ * each thread.
+ */
+ QCryptoBlock *crypto;
} Qcow2PerThreadData;
typedef struct Qcow2ThreadsState {
@@ -711,5 +717,11 @@ qcow2_co_compress(BlockDriverState *bs, void *dest, size_t
dest_size,
ssize_t coroutine_fn
qcow2_co_decompress(BlockDriverState *bs, void *dest, size_t dest_size,
const void *src, size_t src_size);
+int coroutine_fn
+qcow2_co_encrypt(BlockDriverState *bs, uint64_t file_cluster_offset,
+ uint64_t offset, void *buf, size_t len);
+int coroutine_fn
+qcow2_co_decrypt(BlockDriverState *bs, uint64_t file_cluster_offset,
+ uint64_t offset, void *buf, size_t len);
#endif
diff --git a/block/qcow2-threads.c b/block/qcow2-threads.c
index 3ed990ef2f..0a75c1aead 100644
--- a/block/qcow2-threads.c
+++ b/block/qcow2-threads.c
@@ -30,6 +30,7 @@
#include "qcow2.h"
#include "block/thread-pool.h"
+#include "crypto.h"
typedef struct Qcow2ProcessData {
Qcow2PerThreadData *self;
@@ -217,3 +218,64 @@ qcow2_co_decompress(BlockDriverState *bs, void *dest,
size_t dest_size,
return qcow2_co_do_compress(bs, dest, dest_size, src, src_size,
qcow2_decompress);
}
+
+
+/*
+ * Encryption
+ */
+
+typedef int (*Qcow2EncryptFunc)(QCryptoBlock *block, uint64_t offset,
+ uint8_t *buf, size_t len, Error **errp);
+/*
+ * encrypt functions are qcrypto_block_encrypt() and qcrypto_block_decrypt()
+ */
+
+typedef struct Qcow2EncryptData {
+ uint64_t offset;
+ uint8_t *buf;
+ size_t len;
+
+ Qcow2EncryptFunc func;
+} Qcow2EncryptData;
+
+static int qcow2_encrypt_pool_func(void *opaque)
+{
+ Qcow2ProcessData *pdata = opaque;
+ Qcow2EncryptData *data = pdata->arg;
+
+ return data->func(pdata->self->crypto,
+ data->offset, data->buf, data->len, NULL);
+}
+
+static int coroutine_fn
+qcow2_co_do_crypt(BlockDriverState *bs, uint64_t file_cluster_offset,
+ uint64_t offset, void *buf, size_t len, Qcow2EncryptFunc
func)
+{
+ BDRVQcow2State *s = bs->opaque;
+ Qcow2EncryptData arg = {
+ .offset = s->crypt_physical_offset ?
+ file_cluster_offset + offset_into_cluster(s, offset) :
+ offset,
+ .buf = buf,
+ .len = len,
+ .func = func,
+ };
+
+ return qcow2_co_process(bs, qcow2_encrypt_pool_func, &arg);
+}
+
+int coroutine_fn
+qcow2_co_encrypt(BlockDriverState *bs, uint64_t file_cluster_offset,
+ uint64_t offset, void *buf, size_t len)
+{
+ return qcow2_co_do_crypt(bs, file_cluster_offset, offset, buf, len,
+ qcrypto_block_encrypt);
+}
+
+int coroutine_fn
+qcow2_co_decrypt(BlockDriverState *bs, uint64_t file_cluster_offset,
+ uint64_t offset, void *buf, size_t len)
+{
+ return qcow2_co_do_crypt(bs, file_cluster_offset, offset, buf, len,
+ qcrypto_block_decrypt);
+}
diff --git a/block/qcow2.c b/block/qcow2.c
index 295ae926ee..1e28f17373 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -170,6 +170,47 @@ static ssize_t qcow2_crypto_hdr_write_func(QCryptoBlock
*block, size_t offset,
return ret;
}
+static void qcow2_crypto_blocks_free(BDRVQcow2State *s)
+{
+ int i;
+
+ qcrypto_block_free(s->crypto);
+ s->crypto = NULL;
+
+ for (i = 0; i < QCOW2_MAX_THREADS; i++) {
+ qcrypto_block_free(s->threads.per_thread[i].crypto);
+ s->threads.per_thread[i].crypto = NULL;
+ }
+}
+
+static int qcow2_crypto_blocks_open(BDRVQcow2State *s,
+ const char *optprefix,
+ QCryptoBlockReadFunc readfunc,
+ void *opaque,
+ unsigned int flags,
+ Error **errp)
+{
+ int i;
+
+ s->crypto = qcrypto_block_open(s->crypto_opts, optprefix,
+ readfunc, opaque, flags, errp);
+ if (!s->crypto) {
+ qcrypto_block_free(s->crypto);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < QCOW2_MAX_THREADS; i++) {
+ s->threads.per_thread[i].crypto =
+ qcrypto_block_open(s->crypto_opts, optprefix,
+ readfunc, opaque, flags, errp);
+ if (!s->threads.per_thread[i].crypto) {
+ qcow2_crypto_blocks_free(s);
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
/*
* read qcow2 extension and fill bs
@@ -295,11 +336,11 @@ 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, "encrypt.",
+ ret = qcow2_crypto_blocks_open(s, "encrypt.",
qcow2_crypto_hdr_read_func,
bs, cflags, errp);
- if (!s->crypto) {
- return -EINVAL;
+ if (ret < 0) {
+ return ret;
}
} break;
@@ -1446,10 +1487,9 @@ static int coroutine_fn qcow2_do_open(BlockDriverState
*bs, QDict *options,
if (flags & BDRV_O_NO_IO) {
cflags |= QCRYPTO_BLOCK_OPEN_NO_IO;
}
- s->crypto = qcrypto_block_open(s->crypto_opts, "encrypt.",
+ ret = qcow2_crypto_blocks_open(s, "encrypt.",
NULL, NULL, cflags, errp);
- if (!s->crypto) {
- ret = -EINVAL;
+ if (ret < 0) {
goto fail;
}
} else if (!(flags & BDRV_O_NO_IO)) {
@@ -1619,7 +1659,7 @@ static int coroutine_fn qcow2_do_open(BlockDriverState
*bs, QDict *options,
if (s->refcount_block_cache) {
qcow2_cache_destroy(s->refcount_block_cache);
}
- qcrypto_block_free(s->crypto);
+ qcow2_crypto_blocks_free(s);
qapi_free_QCryptoBlockOpenOptions(s->crypto_opts);
return ret;
}
@@ -2214,8 +2254,7 @@ static void qcow2_close(BlockDriverState *bs)
qcow2_cache_destroy(s->l2_table_cache);
qcow2_cache_destroy(s->refcount_block_cache);
- qcrypto_block_free(s->crypto);
- s->crypto = NULL;
+ qcow2_crypto_blocks_free(s);
g_free(s->unknown_header_fields);
cleanup_unknown_header_ext(bs);
--
2.18.0
- [Qemu-block] [PATCH 00/11] qcow2: encryption threads, Vladimir Sementsov-Ogievskiy, 2018/11/23
- [Qemu-block] [PATCH 07/11] qcow2-threads: add encryption,
Vladimir Sementsov-Ogievskiy <=
- [Qemu-block] [PATCH 01/11] qcow2.h: add missing include, Vladimir Sementsov-Ogievskiy, 2018/11/23
- [Qemu-block] [PATCH 05/11] qcow2-threads: split out generic path, Vladimir Sementsov-Ogievskiy, 2018/11/23
- [Qemu-block] [PATCH 08/11] qcow2: bdrv_co_preadv: improve locking, Vladimir Sementsov-Ogievskiy, 2018/11/23
- [Qemu-block] [PATCH 03/11] qcow2-threads: use thread_pool_submit_co, Vladimir Sementsov-Ogievskiy, 2018/11/23
- [Qemu-block] [PATCH 06/11] qcow2-threads: add per-thread data, Vladimir Sementsov-Ogievskiy, 2018/11/23
- [Qemu-block] [PATCH 11/11] qcow2: do encryption in threads, Vladimir Sementsov-Ogievskiy, 2018/11/23
- [Qemu-block] [PATCH 04/11] qcow2: split out data processing threads state from BDRVQcow2State, Vladimir Sementsov-Ogievskiy, 2018/11/23
- [Qemu-block] [PATCH 02/11] qcow2: add separate file for threaded data processing functions, Vladimir Sementsov-Ogievskiy, 2018/11/23
- [Qemu-block] [PATCH 09/11] qcow2: qcow2_co_preadv: skip using hd_qiov when possible, Vladimir Sementsov-Ogievskiy, 2018/11/23