Block patches
-----BEGIN PGP SIGNATURE----- iQEcBAABAgAGBQJZ15OhAAoJEPQH2wBh1c9AELcIAIrqRUvlIWw9VTq53x6sLbJJ dLJ6D2gUaa+ove93dvP8OwES/SDqyxkOZUHZ5ctOXxGYAM6QLfu1Z9Rv9XHhS3Ef gCKdvSuCEHGzYxU7BLbB621syzV71uQk91nXsUEX5jICLKa5wa6XEuqMgsmasa6b K1aQbTLgJ7FeT4EOTXkDMQdQDaa12KPOyEopv9Fy+App1jk/OjlAAMSTz09tcVep eCKn8Q1G51RkaPQPa1yquKz8KOLOYSheSSzg6ujgWUdq4VNeaNUlgjqlVWeK1oWD +3izXFO2dCoBcmRMLT5V4pVXeoK1KdPSNfbM1lb8c4vzwTQyo4g5J3TuP/2QaZg= =LxEj -----END PGP SIGNATURE----- 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>
This commit is contained in:
commit
fc3fd63fc0
130
block/crypto.c
130
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_bytes);
|
||||
|
||||
qemu_iovec_to_buf(qiov, bytes_done,
|
||||
cipher_data, cur_nr_sectors * 512);
|
||||
|
||||
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,
|
||||
|
@ -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);
|
||||
|
11
block/qcow.c
11
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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
@ -240,6 +242,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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user