aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKevin Wolf <kwolf@redhat.com>2017-10-06 16:32:08 +0200
committerKevin Wolf <kwolf@redhat.com>2017-10-06 16:32:08 +0200
commitfc3fd63fc0573ffd2ee569591a2e7f6c7310fd18 (patch)
tree1ba071735ea70c9095cd9ab33d6b8a32f21585f7
parent461743390d3a1ceafa4503811adbc87c7d372741 (diff)
parentce960aa9062a407d0ca15aee3dcd3bd84a4e24f9 (diff)
Merge remote-tracking branch 'mreitz/tags/pull-block-2017-10-06' into queue-block
Block patches # gpg: Signature made Fri Oct 6 16:30:57 2017 CEST # gpg: using RSA key F407DB0061D5CF40 # gpg: Good signature from "Max Reitz <mreitz@redhat.com>" # Primary key fingerprint: 91BE B60A 30DB 3E88 57D1 1829 F407 DB00 61D5 CF40 * mreitz/tags/pull-block-2017-10-06: block/mirror: check backing in bdrv_mirror_top_flush qcow2: truncate the tail of the image file after shrinking the image qcow2: fix return error code in qcow2_truncate() iotests: Fix 195 if IMGFMT is part of TEST_DIR block/mirror: check backing in bdrv_mirror_top_refresh_filename block: support passthrough of BDRV_REQ_FUA in crypto driver block: convert qcrypto_block_encrypt|decrypt to take bytes offset block: convert crypto driver to bdrv_co_preadv|pwritev block: fix data type casting for crypto payload offset crypto: expose encryption sector size in APIs block: use 1 MB bounce buffers for crypto instead of 16KB Signed-off-by: Kevin Wolf <kwolf@redhat.com>
-rw-r--r--block/crypto.c130
-rw-r--r--block/mirror.c9
-rw-r--r--block/qcow.c11
-rw-r--r--block/qcow2-cluster.c8
-rw-r--r--block/qcow2-refcount.c22
-rw-r--r--block/qcow2.c31
-rw-r--r--block/qcow2.h1
-rw-r--r--crypto/block-luks.c18
-rw-r--r--crypto/block-qcow.c13
-rw-r--r--crypto/block.c26
-rw-r--r--crypto/blockpriv.h5
-rw-r--r--include/crypto/block.h29
-rwxr-xr-xtests/qemu-iotests/1957
13 files changed, 209 insertions, 101 deletions
diff --git a/block/crypto.c b/block/crypto.c
index 58ef6f2f52..60ddf8623e 100644
--- a/block/crypto.c
+++ b/block/crypto.c
@@ -279,6 +279,9 @@ static int block_crypto_open_generic(QCryptoBlockFormat format,
return -EINVAL;
}
+ bs->supported_write_flags = BDRV_REQ_FUA &
+ bs->file->bs->supported_write_flags;
+
opts = qemu_opts_create(opts_spec, NULL, 0, &error_abort);
qemu_opts_absorb_qdict(opts, options, &local_err);
if (local_err) {
@@ -364,8 +367,9 @@ static int block_crypto_truncate(BlockDriverState *bs, int64_t offset,
PreallocMode prealloc, Error **errp)
{
BlockCrypto *crypto = bs->opaque;
- size_t payload_offset =
+ uint64_t payload_offset =
qcrypto_block_get_payload_offset(crypto->block);
+ assert(payload_offset < (INT64_MAX - offset));
offset += payload_offset;
@@ -379,66 +383,65 @@ static void block_crypto_close(BlockDriverState *bs)
}
-#define BLOCK_CRYPTO_MAX_SECTORS 32
+/*
+ * 1 MB bounce buffer gives good performance / memory tradeoff
+ * when using cache=none|directsync.
+ */
+#define BLOCK_CRYPTO_MAX_IO_SIZE (1024 * 1024)
static coroutine_fn int
-block_crypto_co_readv(BlockDriverState *bs, int64_t sector_num,
- int remaining_sectors, QEMUIOVector *qiov)
+block_crypto_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
+ QEMUIOVector *qiov, int flags)
{
BlockCrypto *crypto = bs->opaque;
- int cur_nr_sectors; /* number of sectors in current iteration */
+ uint64_t cur_bytes; /* number of bytes in current iteration */
uint64_t bytes_done = 0;
uint8_t *cipher_data = NULL;
QEMUIOVector hd_qiov;
int ret = 0;
- size_t payload_offset =
- qcrypto_block_get_payload_offset(crypto->block) / 512;
+ uint64_t sector_size = qcrypto_block_get_sector_size(crypto->block);
+ uint64_t payload_offset = qcrypto_block_get_payload_offset(crypto->block);
+
+ assert(!flags);
+ assert(payload_offset < INT64_MAX);
+ assert(QEMU_IS_ALIGNED(offset, sector_size));
+ assert(QEMU_IS_ALIGNED(bytes, sector_size));
qemu_iovec_init(&hd_qiov, qiov->niov);
- /* Bounce buffer so we have a linear mem region for
- * entire sector. XXX optimize so we avoid bounce
- * buffer in case that qiov->niov == 1
+ /* Bounce buffer because we don't wish to expose cipher text
+ * in qiov which points to guest memory.
*/
cipher_data =
- qemu_try_blockalign(bs->file->bs, MIN(BLOCK_CRYPTO_MAX_SECTORS * 512,
+ qemu_try_blockalign(bs->file->bs, MIN(BLOCK_CRYPTO_MAX_IO_SIZE,
qiov->size));
if (cipher_data == NULL) {
ret = -ENOMEM;
goto cleanup;
}
- while (remaining_sectors) {
- cur_nr_sectors = remaining_sectors;
-
- if (cur_nr_sectors > BLOCK_CRYPTO_MAX_SECTORS) {
- cur_nr_sectors = BLOCK_CRYPTO_MAX_SECTORS;
- }
+ while (bytes) {
+ cur_bytes = MIN(bytes, BLOCK_CRYPTO_MAX_IO_SIZE);
qemu_iovec_reset(&hd_qiov);
- qemu_iovec_add(&hd_qiov, cipher_data, cur_nr_sectors * 512);
+ qemu_iovec_add(&hd_qiov, cipher_data, cur_bytes);
- ret = bdrv_co_readv(bs->file,
- payload_offset + sector_num,
- cur_nr_sectors, &hd_qiov);
+ ret = bdrv_co_preadv(bs->file, payload_offset + offset + bytes_done,
+ cur_bytes, &hd_qiov, 0);
if (ret < 0) {
goto cleanup;
}
- if (qcrypto_block_decrypt(crypto->block,
- sector_num,
- cipher_data, cur_nr_sectors * 512,
- NULL) < 0) {
+ if (qcrypto_block_decrypt(crypto->block, offset + bytes_done,
+ cipher_data, cur_bytes, NULL) < 0) {
ret = -EIO;
goto cleanup;
}
- qemu_iovec_from_buf(qiov, bytes_done,
- cipher_data, cur_nr_sectors * 512);
+ qemu_iovec_from_buf(qiov, bytes_done, cipher_data, cur_bytes);
- remaining_sectors -= cur_nr_sectors;
- sector_num += cur_nr_sectors;
- bytes_done += cur_nr_sectors * 512;
+ bytes -= cur_bytes;
+ bytes_done += cur_bytes;
}
cleanup:
@@ -450,63 +453,58 @@ block_crypto_co_readv(BlockDriverState *bs, int64_t sector_num,
static coroutine_fn int
-block_crypto_co_writev(BlockDriverState *bs, int64_t sector_num,
- int remaining_sectors, QEMUIOVector *qiov)
+block_crypto_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
+ QEMUIOVector *qiov, int flags)
{
BlockCrypto *crypto = bs->opaque;
- int cur_nr_sectors; /* number of sectors in current iteration */
+ uint64_t cur_bytes; /* number of bytes in current iteration */
uint64_t bytes_done = 0;
uint8_t *cipher_data = NULL;
QEMUIOVector hd_qiov;
int ret = 0;
- size_t payload_offset =
- qcrypto_block_get_payload_offset(crypto->block) / 512;
+ uint64_t sector_size = qcrypto_block_get_sector_size(crypto->block);
+ uint64_t payload_offset = qcrypto_block_get_payload_offset(crypto->block);
+
+ assert(!(flags & ~BDRV_REQ_FUA));
+ assert(payload_offset < INT64_MAX);
+ assert(QEMU_IS_ALIGNED(offset, sector_size));
+ assert(QEMU_IS_ALIGNED(bytes, sector_size));
qemu_iovec_init(&hd_qiov, qiov->niov);
- /* Bounce buffer so we have a linear mem region for
- * entire sector. XXX optimize so we avoid bounce
- * buffer in case that qiov->niov == 1
+ /* Bounce buffer because we're not permitted to touch
+ * contents of qiov - it points to guest memory.
*/
cipher_data =
- qemu_try_blockalign(bs->file->bs, MIN(BLOCK_CRYPTO_MAX_SECTORS * 512,
+ qemu_try_blockalign(bs->file->bs, MIN(BLOCK_CRYPTO_MAX_IO_SIZE,
qiov->size));
if (cipher_data == NULL) {
ret = -ENOMEM;
goto cleanup;
}
- while (remaining_sectors) {
- cur_nr_sectors = remaining_sectors;
+ while (bytes) {
+ cur_bytes = MIN(bytes, BLOCK_CRYPTO_MAX_IO_SIZE);
- if (cur_nr_sectors > BLOCK_CRYPTO_MAX_SECTORS) {
- cur_nr_sectors = BLOCK_CRYPTO_MAX_SECTORS;
- }
-
- qemu_iovec_to_buf(qiov, bytes_done,
- cipher_data, cur_nr_sectors * 512);
+ qemu_iovec_to_buf(qiov, bytes_done, cipher_data, cur_bytes);
- if (qcrypto_block_encrypt(crypto->block,
- sector_num,
- cipher_data, cur_nr_sectors * 512,
- NULL) < 0) {
+ if (qcrypto_block_encrypt(crypto->block, offset + bytes_done,
+ cipher_data, cur_bytes, NULL) < 0) {
ret = -EIO;
goto cleanup;
}
qemu_iovec_reset(&hd_qiov);
- qemu_iovec_add(&hd_qiov, cipher_data, cur_nr_sectors * 512);
+ qemu_iovec_add(&hd_qiov, cipher_data, cur_bytes);
- ret = bdrv_co_writev(bs->file,
- payload_offset + sector_num,
- cur_nr_sectors, &hd_qiov);
+ ret = bdrv_co_pwritev(bs->file, payload_offset + offset + bytes_done,
+ cur_bytes, &hd_qiov, flags);
if (ret < 0) {
goto cleanup;
}
- remaining_sectors -= cur_nr_sectors;
- sector_num += cur_nr_sectors;
- bytes_done += cur_nr_sectors * 512;
+ bytes -= cur_bytes;
+ bytes_done += cur_bytes;
}
cleanup:
@@ -516,13 +514,22 @@ block_crypto_co_writev(BlockDriverState *bs, int64_t sector_num,
return ret;
}
+static void block_crypto_refresh_limits(BlockDriverState *bs, Error **errp)
+{
+ BlockCrypto *crypto = bs->opaque;
+ uint64_t sector_size = qcrypto_block_get_sector_size(crypto->block);
+ bs->bl.request_alignment = sector_size; /* No sub-sector I/O */
+}
+
static int64_t block_crypto_getlength(BlockDriverState *bs)
{
BlockCrypto *crypto = bs->opaque;
int64_t len = bdrv_getlength(bs->file->bs);
- ssize_t offset = qcrypto_block_get_payload_offset(crypto->block);
+ uint64_t offset = qcrypto_block_get_payload_offset(crypto->block);
+ assert(offset < INT64_MAX);
+ assert(offset < len);
len -= offset;
@@ -613,8 +620,9 @@ BlockDriver bdrv_crypto_luks = {
.bdrv_truncate = block_crypto_truncate,
.create_opts = &block_crypto_create_opts_luks,
- .bdrv_co_readv = block_crypto_co_readv,
- .bdrv_co_writev = block_crypto_co_writev,
+ .bdrv_refresh_limits = block_crypto_refresh_limits,
+ .bdrv_co_preadv = block_crypto_co_preadv,
+ .bdrv_co_pwritev = block_crypto_co_pwritev,
.bdrv_getlength = block_crypto_getlength,
.bdrv_get_info = block_crypto_get_info_luks,
.bdrv_get_specific_info = block_crypto_get_specific_info_luks,
diff --git a/block/mirror.c b/block/mirror.c
index 459b80f8f3..153758ca9f 100644
--- a/block/mirror.c
+++ b/block/mirror.c
@@ -1041,6 +1041,10 @@ static int coroutine_fn bdrv_mirror_top_pwritev(BlockDriverState *bs,
static int coroutine_fn bdrv_mirror_top_flush(BlockDriverState *bs)
{
+ if (bs->backing == NULL) {
+ /* we can be here after failed bdrv_append in mirror_start_job */
+ return 0;
+ }
return bdrv_co_flush(bs->backing->bs);
}
@@ -1058,6 +1062,11 @@ static int coroutine_fn bdrv_mirror_top_pdiscard(BlockDriverState *bs,
static void bdrv_mirror_top_refresh_filename(BlockDriverState *bs, QDict *opts)
{
+ if (bs->backing == NULL) {
+ /* we can be here after failed bdrv_attach_child in
+ * bdrv_set_backing_hd */
+ return;
+ }
bdrv_refresh_filename(bs->backing->bs);
pstrcpy(bs->exact_filename, sizeof(bs->exact_filename),
bs->backing->bs->filename);
diff --git a/block/qcow.c b/block/qcow.c
index f450b00cfc..9569deeaf0 100644
--- a/block/qcow.c
+++ b/block/qcow.c
@@ -478,7 +478,9 @@ static int get_cluster_offset(BlockDriverState *bs,
for(i = 0; i < s->cluster_sectors; i++) {
if (i < n_start || i >= n_end) {
memset(s->cluster_data, 0x00, 512);
- if (qcrypto_block_encrypt(s->crypto, start_sect + i,
+ if (qcrypto_block_encrypt(s->crypto,
+ (start_sect + i) *
+ BDRV_SECTOR_SIZE,
s->cluster_data,
BDRV_SECTOR_SIZE,
NULL) < 0) {
@@ -668,7 +670,8 @@ static coroutine_fn int qcow_co_readv(BlockDriverState *bs, int64_t sector_num,
}
if (bs->encrypted) {
assert(s->crypto);
- if (qcrypto_block_decrypt(s->crypto, sector_num, buf,
+ if (qcrypto_block_decrypt(s->crypto,
+ sector_num * BDRV_SECTOR_SIZE, buf,
n * BDRV_SECTOR_SIZE, NULL) < 0) {
ret = -EIO;
break;
@@ -740,8 +743,8 @@ static coroutine_fn int qcow_co_writev(BlockDriverState *bs, int64_t sector_num,
}
if (bs->encrypted) {
assert(s->crypto);
- if (qcrypto_block_encrypt(s->crypto, sector_num, buf,
- n * BDRV_SECTOR_SIZE, NULL) < 0) {
+ if (qcrypto_block_encrypt(s->crypto, sector_num * BDRV_SECTOR_SIZE,
+ buf, n * BDRV_SECTOR_SIZE, NULL) < 0) {
ret = -EIO;
break;
}
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index d2518d1893..0e5aec81cb 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -446,15 +446,13 @@ static bool coroutine_fn do_perform_cow_encrypt(BlockDriverState *bs,
{
if (bytes && bs->encrypted) {
BDRVQcow2State *s = bs->opaque;
- int64_t sector = (s->crypt_physical_offset ?
+ int64_t offset = (s->crypt_physical_offset ?
(cluster_offset + offset_in_cluster) :
- (src_cluster_offset + offset_in_cluster))
- >> BDRV_SECTOR_BITS;
+ (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, sector, buffer,
- bytes, NULL) < 0) {
+ if (qcrypto_block_encrypt(s->crypto, offset, buffer, bytes, NULL) < 0) {
return false;
}
}
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
index 88d5a3f1ad..aa3fd6cf17 100644
--- a/block/qcow2-refcount.c
+++ b/block/qcow2-refcount.c
@@ -3181,3 +3181,25 @@ out:
g_free(reftable_tmp);
return ret;
}
+
+int64_t qcow2_get_last_cluster(BlockDriverState *bs, int64_t size)
+{
+ BDRVQcow2State *s = bs->opaque;
+ int64_t i;
+
+ for (i = size_to_clusters(s, size) - 1; i >= 0; i--) {
+ uint64_t refcount;
+ int ret = qcow2_get_refcount(bs, i, &refcount);
+ if (ret < 0) {
+ fprintf(stderr, "Can't get refcount for cluster %" PRId64 ": %s\n",
+ i, strerror(-ret));
+ return ret;
+ }
+ if (refcount > 0) {
+ return i;
+ }
+ }
+ qcow2_signal_corruption(bs, true, -1, -1,
+ "There are no references in the refcount table.");
+ return -EIO;
+}
diff --git a/block/qcow2.c b/block/qcow2.c
index b8da8ca105..f63d1831f8 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -1811,7 +1811,7 @@ static coroutine_fn int qcow2_co_preadv(BlockDriverState *bs, uint64_t offset,
if (qcrypto_block_decrypt(s->crypto,
(s->crypt_physical_offset ?
cluster_offset + offset_in_cluster :
- offset) >> BDRV_SECTOR_BITS,
+ offset),
cluster_data,
cur_bytes,
NULL) < 0) {
@@ -1946,7 +1946,7 @@ static coroutine_fn int qcow2_co_pwritev(BlockDriverState *bs, uint64_t offset,
if (qcrypto_block_encrypt(s->crypto,
(s->crypt_physical_offset ?
cluster_offset + offset_in_cluster :
- offset) >> BDRV_SECTOR_BITS,
+ offset),
cluster_data,
cur_bytes, NULL) < 0) {
ret = -EIO;
@@ -3107,6 +3107,7 @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset,
new_l1_size = size_to_l1(s, offset);
if (offset < old_length) {
+ int64_t last_cluster, old_file_size;
if (prealloc != PREALLOC_MODE_OFF) {
error_setg(errp,
"Preallocation can't be used for shrinking an image");
@@ -3135,6 +3136,28 @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset,
"Failed to discard unused refblocks");
return ret;
}
+
+ 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 old_file_size;
+ }
+ last_cluster = qcow2_get_last_cluster(bs, old_file_size);
+ if (last_cluster < 0) {
+ error_setg_errno(errp, -last_cluster,
+ "Failed to find the last cluster");
+ return last_cluster;
+ }
+ if ((last_cluster + 1) * s->cluster_size < old_file_size) {
+ ret = bdrv_truncate(bs->file, (last_cluster + 1) * s->cluster_size,
+ PREALLOC_MODE_OFF, NULL);
+ if (ret < 0) {
+ warn_report("Failed to truncate the tail of the image: %s",
+ strerror(-ret));
+ ret = 0;
+ }
+ }
} else {
ret = qcow2_grow_l1_table(bs, new_l1_size, true);
if (ret < 0) {
@@ -3167,7 +3190,7 @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset,
if (old_file_size < 0) {
error_setg_errno(errp, -old_file_size,
"Failed to inquire current file length");
- return ret;
+ return old_file_size;
}
nb_new_data_clusters = DIV_ROUND_UP(offset - old_length,
@@ -3196,7 +3219,7 @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset,
if (allocation_start < 0) {
error_setg_errno(errp, -allocation_start,
"Failed to resize refcount structures");
- return -allocation_start;
+ return allocation_start;
}
clusters_allocated = qcow2_alloc_clusters_at(bs, allocation_start,
diff --git a/block/qcow2.h b/block/qcow2.h
index 5a289a81e2..782a206ecb 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -597,6 +597,7 @@ int qcow2_change_refcount_order(BlockDriverState *bs, int refcount_order,
BlockDriverAmendStatusCB *status_cb,
void *cb_opaque, Error **errp);
int qcow2_shrink_reftable(BlockDriverState *bs);
+int64_t qcow2_get_last_cluster(BlockDriverState *bs, int64_t size);
/* qcow2-cluster.c functions */
int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size,
diff --git a/crypto/block-luks.c b/crypto/block-luks.c
index 36bc856084..d418ac30b8 100644
--- a/crypto/block-luks.c
+++ b/crypto/block-luks.c
@@ -846,8 +846,9 @@ qcrypto_block_luks_open(QCryptoBlock *block,
}
}
+ block->sector_size = QCRYPTO_BLOCK_LUKS_SECTOR_SIZE;
block->payload_offset = luks->header.payload_offset *
- QCRYPTO_BLOCK_LUKS_SECTOR_SIZE;
+ block->sector_size;
luks->cipher_alg = cipheralg;
luks->cipher_mode = ciphermode;
@@ -1240,8 +1241,9 @@ qcrypto_block_luks_create(QCryptoBlock *block,
QCRYPTO_BLOCK_LUKS_SECTOR_SIZE)) *
QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS);
+ block->sector_size = QCRYPTO_BLOCK_LUKS_SECTOR_SIZE;
block->payload_offset = luks->header.payload_offset *
- QCRYPTO_BLOCK_LUKS_SECTOR_SIZE;
+ block->sector_size;
/* Reserve header space to match payload offset */
initfunc(block, block->payload_offset, opaque, &local_err);
@@ -1397,29 +1399,33 @@ static void qcrypto_block_luks_cleanup(QCryptoBlock *block)
static int
qcrypto_block_luks_decrypt(QCryptoBlock *block,
- uint64_t startsector,
+ uint64_t offset,
uint8_t *buf,
size_t len,
Error **errp)
{
+ assert(QEMU_IS_ALIGNED(offset, QCRYPTO_BLOCK_LUKS_SECTOR_SIZE));
+ assert(QEMU_IS_ALIGNED(len, QCRYPTO_BLOCK_LUKS_SECTOR_SIZE));
return qcrypto_block_decrypt_helper(block->cipher,
block->niv, block->ivgen,
QCRYPTO_BLOCK_LUKS_SECTOR_SIZE,
- startsector, buf, len, errp);
+ offset, buf, len, errp);
}
static int
qcrypto_block_luks_encrypt(QCryptoBlock *block,
- uint64_t startsector,
+ uint64_t offset,
uint8_t *buf,
size_t len,
Error **errp)
{
+ assert(QEMU_IS_ALIGNED(offset, QCRYPTO_BLOCK_LUKS_SECTOR_SIZE));
+ assert(QEMU_IS_ALIGNED(len, QCRYPTO_BLOCK_LUKS_SECTOR_SIZE));
return qcrypto_block_encrypt_helper(block->cipher,
block->niv, block->ivgen,
QCRYPTO_BLOCK_LUKS_SECTOR_SIZE,
- startsector, buf, len, errp);
+ offset, buf, len, errp);
}
diff --git a/crypto/block-qcow.c b/crypto/block-qcow.c
index a456fe338b..8817d6aaa7 100644
--- a/crypto/block-qcow.c
+++ b/crypto/block-qcow.c
@@ -80,6 +80,7 @@ qcrypto_block_qcow_init(QCryptoBlock *block,
goto fail;
}
+ block->sector_size = QCRYPTO_BLOCK_QCOW_SECTOR_SIZE;
block->payload_offset = 0;
return 0;
@@ -142,29 +143,33 @@ qcrypto_block_qcow_cleanup(QCryptoBlock *block)
static int
qcrypto_block_qcow_decrypt(QCryptoBlock *block,
- uint64_t startsector,
+ uint64_t offset,
uint8_t *buf,
size_t len,
Error **errp)
{
+ assert(QEMU_IS_ALIGNED(offset, QCRYPTO_BLOCK_QCOW_SECTOR_SIZE));
+ assert(QEMU_IS_ALIGNED(len, QCRYPTO_BLOCK_QCOW_SECTOR_SIZE));
return qcrypto_block_decrypt_helper(block->cipher,
block->niv, block->ivgen,
QCRYPTO_BLOCK_QCOW_SECTOR_SIZE,
- startsector, buf, len, errp);
+ offset, buf, len, errp);
}
static int
qcrypto_block_qcow_encrypt(QCryptoBlock *block,
- uint64_t startsector,
+ uint64_t offset,
uint8_t *buf,
size_t len,
Error **errp)
{
+ assert(QEMU_IS_ALIGNED(offset, QCRYPTO_BLOCK_QCOW_SECTOR_SIZE));
+ assert(QEMU_IS_ALIGNED(len, QCRYPTO_BLOCK_QCOW_SECTOR_SIZE));
return qcrypto_block_encrypt_helper(block->cipher,
block->niv, block->ivgen,
QCRYPTO_BLOCK_QCOW_SECTOR_SIZE,
- startsector, buf, len, errp);
+ offset, buf, len, errp);
}
diff --git a/crypto/block.c b/crypto/block.c
index c382393d9a..f206d5eea8 100644
--- a/crypto/block.c
+++ b/crypto/block.c
@@ -127,22 +127,22 @@ QCryptoBlockInfo *qcrypto_block_get_info(QCryptoBlock *block,
int qcrypto_block_decrypt(QCryptoBlock *block,
- uint64_t startsector,
+ uint64_t offset,
uint8_t *buf,
size_t len,
Error **errp)
{
- return block->driver->decrypt(block, startsector, buf, len, errp);
+ return block->driver->decrypt(block, offset, buf, len, errp);
}
int qcrypto_block_encrypt(QCryptoBlock *block,
- uint64_t startsector,
+ uint64_t offset,
uint8_t *buf,
size_t len,
Error **errp)
{
- return block->driver->encrypt(block, startsector, buf, len, errp);
+ return block->driver->encrypt(block, offset, buf, len, errp);
}
@@ -170,6 +170,12 @@ uint64_t qcrypto_block_get_payload_offset(QCryptoBlock *block)
}
+uint64_t qcrypto_block_get_sector_size(QCryptoBlock *block)
+{
+ return block->sector_size;
+}
+
+
void qcrypto_block_free(QCryptoBlock *block)
{
if (!block) {
@@ -188,13 +194,17 @@ int qcrypto_block_decrypt_helper(QCryptoCipher *cipher,
size_t niv,
QCryptoIVGen *ivgen,
int sectorsize,
- uint64_t startsector,
+ uint64_t offset,
uint8_t *buf,
size_t len,
Error **errp)
{
uint8_t *iv;
int ret = -1;
+ uint64_t startsector = offset / sectorsize;
+
+ assert(QEMU_IS_ALIGNED(offset, sectorsize));
+ assert(QEMU_IS_ALIGNED(len, sectorsize));
iv = niv ? g_new0(uint8_t, niv) : NULL;
@@ -237,13 +247,17 @@ int qcrypto_block_encrypt_helper(QCryptoCipher *cipher,
size_t niv,
QCryptoIVGen *ivgen,
int sectorsize,
- uint64_t startsector,
+ uint64_t offset,
uint8_t *buf,
size_t len,
Error **errp)
{
uint8_t *iv;
int ret = -1;
+ uint64_t startsector = offset / sectorsize;
+
+ assert(QEMU_IS_ALIGNED(offset, sectorsize));
+ assert(QEMU_IS_ALIGNED(len, sectorsize));
iv = niv ? g_new0(uint8_t, niv) : NULL;
diff --git a/crypto/blockpriv.h b/crypto/blockpriv.h
index 0edb810e22..41840abcec 100644
--- a/crypto/blockpriv.h
+++ b/crypto/blockpriv.h
@@ -36,6 +36,7 @@ struct QCryptoBlock {
QCryptoHashAlgorithm kdfhash;
size_t niv;
uint64_t payload_offset; /* In bytes */
+ uint64_t sector_size; /* In bytes */
};
struct QCryptoBlockDriver {
@@ -81,7 +82,7 @@ int qcrypto_block_decrypt_helper(QCryptoCipher *cipher,
size_t niv,
QCryptoIVGen *ivgen,
int sectorsize,
- uint64_t startsector,
+ uint64_t offset,
uint8_t *buf,
size_t len,
Error **errp);
@@ -90,7 +91,7 @@ int qcrypto_block_encrypt_helper(QCryptoCipher *cipher,
size_t niv,
QCryptoIVGen *ivgen,
int sectorsize,
- uint64_t startsector,
+ uint64_t offset,
uint8_t *buf,
size_t len,
Error **errp);
diff --git a/include/crypto/block.h b/include/crypto/block.h
index f0e543bee1..cd18f46d56 100644
--- a/include/crypto/block.h
+++ b/include/crypto/block.h
@@ -161,18 +161,19 @@ QCryptoBlockInfo *qcrypto_block_get_info(QCryptoBlock *block,
/**
* @qcrypto_block_decrypt:
* @block: the block encryption object
- * @startsector: the sector from which @buf was read
+ * @offset: the position at which @iov was read
* @buf: the buffer to decrypt
* @len: the length of @buf in bytes
* @errp: pointer to a NULL-initialized error object
*
* Decrypt @len bytes of cipher text in @buf, writing
- * plain text back into @buf
+ * plain text back into @buf. @len and @offset must be
+ * a multiple of the encryption format sector size.
*
* Returns 0 on success, -1 on failure
*/
int qcrypto_block_decrypt(QCryptoBlock *block,
- uint64_t startsector,
+ uint64_t offset,
uint8_t *buf,
size_t len,
Error **errp);
@@ -180,18 +181,19 @@ int qcrypto_block_decrypt(QCryptoBlock *block,
/**
* @qcrypto_block_encrypt:
* @block: the block encryption object
- * @startsector: the sector to which @buf will be written
+ * @offset: the position at which @iov will be written
* @buf: the buffer to decrypt
* @len: the length of @buf in bytes
* @errp: pointer to a NULL-initialized error object
*
* Encrypt @len bytes of plain text in @buf, writing
- * cipher text back into @buf
+ * cipher text back into @buf. @len and @offset must be
+ * a multiple of the encryption format sector size.
*
* Returns 0 on success, -1 on failure
*/
int qcrypto_block_encrypt(QCryptoBlock *block,
- uint64_t startsector,
+ uint64_t offset,
uint8_t *buf,
size_t len,
Error **errp);
@@ -241,6 +243,21 @@ QCryptoHashAlgorithm qcrypto_block_get_kdf_hash(QCryptoBlock *block);
uint64_t qcrypto_block_get_payload_offset(QCryptoBlock *block);
/**
+ * qcrypto_block_get_sector_size:
+ * @block: the block encryption object
+ *
+ * Get the size of sectors used for payload encryption. A new
+ * IV is used at the start of each sector. The encryption
+ * sector size is not required to match the sector size of the
+ * underlying storage. For example LUKS will always use a 512
+ * byte sector size, even if the volume is on a disk with 4k
+ * sectors.
+ *
+ * Returns: the sector in bytes
+ */
+uint64_t qcrypto_block_get_sector_size(QCryptoBlock *block);
+
+/**
* qcrypto_block_free:
* @block: the block encryption object
*
diff --git a/tests/qemu-iotests/195 b/tests/qemu-iotests/195
index 05a239cbf5..e7a403ded2 100755
--- a/tests/qemu-iotests/195
+++ b/tests/qemu-iotests/195
@@ -44,15 +44,16 @@ _supported_os Linux
function do_run_qemu()
{
- echo Testing: "$@" | _filter_imgfmt
+ echo Testing: "$@"
$QEMU -nographic -qmp-pretty stdio -serial none "$@"
echo
}
function run_qemu()
{
- do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qemu | _filter_qmp \
- | _filter_qemu_io | _filter_generated_node_ids
+ do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_imgfmt | _filter_qemu \
+ | _filter_qmp | _filter_qemu_io \
+ | _filter_generated_node_ids
}
size=64M