Commit 8ac0f15f authored by Vladimir Sementsov-Ogievskiy's avatar Vladimir Sementsov-Ogievskiy Committed by Max Reitz
Browse files

qcow2: do encryption in threads



Do encryption/decryption in threads, like it is already done for
compression. This improves asynchronous encrypted io.

Signed-off-by: default avatarVladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Reviewed-by: default avatarAlberto Garcia <berto@igalia.com>
Reviewed-by: default avatarMax Reitz <mreitz@redhat.com>
Message-id: 20190506142741.41731-9-vsementsov@virtuozzo.com
Signed-off-by: default avatarMax Reitz <mreitz@redhat.com>
parent 5447c3a0
Loading
Loading
Loading
Loading
+3 −4
Original line number Diff line number Diff line
@@ -471,13 +471,12 @@ static bool coroutine_fn do_perform_cow_encrypt(BlockDriverState *bs,
{
    if (bytes && bs->encrypted) {
        BDRVQcow2State *s = bs->opaque;
        int64_t offset = (s->crypt_physical_offset ?
                          (cluster_offset + offset_in_cluster) :
                          (src_cluster_offset + offset_in_cluster));
        assert((offset_in_cluster & ~BDRV_SECTOR_MASK) == 0);
        assert((bytes & ~BDRV_SECTOR_MASK) == 0);
        assert(s->crypto);
        if (qcrypto_block_encrypt(s->crypto, offset, buffer, bytes, NULL) < 0) {
        if (qcow2_co_encrypt(bs, cluster_offset,
                             src_cluster_offset + offset_in_cluster,
                             buffer, bytes) < 0) {
            return false;
        }
    }
+63 −2
Original line number Diff line number Diff line
@@ -30,8 +30,7 @@

#include "qcow2.h"
#include "block/thread-pool.h"

#define QCOW2_MAX_THREADS 4
#include "crypto.h"

static int coroutine_fn
qcow2_co_process(BlockDriverState *bs, ThreadPoolFunc *func, void *arg)
@@ -205,3 +204,65 @@ 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);
}


/*
 * Cryptography
 */

/*
 * Qcow2EncDecFunc: common prototype of qcrypto_block_encrypt() and
 * qcrypto_block_decrypt() functions.
 */
typedef int (*Qcow2EncDecFunc)(QCryptoBlock *block, uint64_t offset,
                               uint8_t *buf, size_t len, Error **errp);

typedef struct Qcow2EncDecData {
    QCryptoBlock *block;
    uint64_t offset;
    uint8_t *buf;
    size_t len;

    Qcow2EncDecFunc func;
} Qcow2EncDecData;

static int qcow2_encdec_pool_func(void *opaque)
{
    Qcow2EncDecData *data = opaque;

    return data->func(data->block, data->offset, data->buf, data->len, NULL);
}

static int coroutine_fn
qcow2_co_encdec(BlockDriverState *bs, uint64_t file_cluster_offset,
                  uint64_t offset, void *buf, size_t len, Qcow2EncDecFunc func)
{
    BDRVQcow2State *s = bs->opaque;
    Qcow2EncDecData arg = {
        .block = s->crypto,
        .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_encdec_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_encdec(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_encdec(bs, file_cluster_offset, offset, buf, len,
                             qcrypto_block_decrypt);
}
+7 −15
Original line number Diff line number Diff line
@@ -297,7 +297,7 @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
            }
            s->crypto = qcrypto_block_open(s->crypto_opts, "encrypt.",
                                           qcow2_crypto_hdr_read_func,
                                           bs, cflags, 1, errp);
                                           bs, cflags, QCOW2_MAX_THREADS, errp);
            if (!s->crypto) {
                return -EINVAL;
            }
@@ -1538,7 +1538,8 @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
                cflags |= QCRYPTO_BLOCK_OPEN_NO_IO;
            }
            s->crypto = qcrypto_block_open(s->crypto_opts, "encrypt.",
                                           NULL, NULL, cflags, 1, errp);
                                           NULL, NULL, cflags,
                                           QCOW2_MAX_THREADS, errp);
            if (!s->crypto) {
                ret = -EINVAL;
                goto fail;
@@ -2061,13 +2062,8 @@ static coroutine_fn int qcow2_co_preadv(BlockDriverState *bs, uint64_t offset,
                assert(s->crypto);
                assert((offset & (BDRV_SECTOR_SIZE - 1)) == 0);
                assert((cur_bytes & (BDRV_SECTOR_SIZE - 1)) == 0);
                if (qcrypto_block_decrypt(s->crypto,
                                          (s->crypt_physical_offset ?
                                           cluster_offset + offset_in_cluster :
                                           offset),
                                          cluster_data,
                                          cur_bytes,
                                          NULL) < 0) {
                if (qcow2_co_decrypt(bs, cluster_offset, offset,
                                     cluster_data, cur_bytes) < 0) {
                    ret = -EIO;
                    goto fail;
                }
@@ -2201,12 +2197,8 @@ 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,
                                      (s->crypt_physical_offset ?
                                       cluster_offset + offset_in_cluster :
                                       offset),
                                      cluster_data,
                                      cur_bytes, NULL) < 0) {
            if (qcow2_co_encrypt(bs, cluster_offset, offset,
                                 cluster_data, cur_bytes) < 0) {
                ret = -EIO;
                goto out_unlocked;
            }
+8 −0
Original line number Diff line number Diff line
@@ -268,6 +268,8 @@ typedef struct Qcow2BitmapHeaderExt {
    uint64_t bitmap_directory_offset;
} QEMU_PACKED Qcow2BitmapHeaderExt;

#define QCOW2_MAX_THREADS 4

typedef struct BDRVQcow2State {
    int cluster_bits;
    int cluster_size;
@@ -744,5 +746,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