Merge remote-tracking branch 'remotes/maxreitz/tags/pull-block-2020-07-06' into staging

Block patches for 5.1:
- LUKS keyslot amendment
  (+ patches to make the iotests pass on non-Linux systems, and to keep
     the tests passing for qcow v1, and to skip LUKS tests (including
     qcow2 LUKS) when the built qemu does not support it)
- Refactoring in the block layer: Drop the basically unnecessary
  unallocated_blocks_are_zero field from BlockDriverInfo
- Fix qcow2 preallocation when the image size is not a multiple of the
  cluster size
- Fix in block-copy code

# gpg: Signature made Mon 06 Jul 2020 11:02:53 BST
# gpg:                using RSA key 91BEB60A30DB3E8857D11829F407DB0061D5CF40
# gpg:                issuer "mreitz@redhat.com"
# gpg: Good signature from "Max Reitz <mreitz@redhat.com>" [full]
# Primary key fingerprint: 91BE B60A 30DB 3E88 57D1  1829 F407 DB00 61D5 CF40

* remotes/maxreitz/tags/pull-block-2020-07-06: (31 commits)
  qed: Simplify backing reads
  block: drop unallocated_blocks_are_zero
  block/vhdx: drop unallocated_blocks_are_zero
  block/file-posix: drop unallocated_blocks_are_zero
  block/iscsi: drop unallocated_blocks_are_zero
  block/crypto: drop unallocated_blocks_are_zero
  block/vpc: return ZERO block-status when appropriate
  block/vdi: return ZERO block-status when appropriate
  block: inline bdrv_unallocated_blocks_are_zero()
  qemu-img: convert: don't use unallocated_blocks_are_zero
  iotests: add tests for blockdev-amend
  block/qcow2: implement blockdev-amend
  block/crypto: implement blockdev-amend
  block/core: add generic infrastructure for x-blockdev-amend qmp command
  iotests: qemu-img tests for luks key management
  block/qcow2: extend qemu-img amend interface with crypto options
  block/crypto: implement the encryption key management
  block/crypto: rename two functions
  block/amend: refactor qcow2 amend options
  block/amend: separate amend and create options for qemu-img
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell
2020-07-07 19:47:26 +01:00
72 changed files with 3105 additions and 634 deletions
+3 -16
View File
@@ -5408,21 +5408,6 @@ int bdrv_has_zero_init(BlockDriverState *bs)
return 0;
}
bool bdrv_unallocated_blocks_are_zero(BlockDriverState *bs)
{
BlockDriverInfo bdi;
if (bs->backing) {
return false;
}
if (bdrv_get_info(bs, &bdi) == 0) {
return bdi.unallocated_blocks_are_zero;
}
return false;
}
bool bdrv_can_write_zeroes_with_unmap(BlockDriverState *bs)
{
if (!(bs->open_flags & BDRV_O_UNMAP)) {
@@ -6482,6 +6467,7 @@ void bdrv_remove_aio_context_notifier(BlockDriverState *bs,
int bdrv_amend_options(BlockDriverState *bs, QemuOpts *opts,
BlockDriverAmendStatusCB *status_cb, void *cb_opaque,
bool force,
Error **errp)
{
if (!bs->drv) {
@@ -6493,7 +6479,8 @@ int bdrv_amend_options(BlockDriverState *bs, QemuOpts *opts,
bs->drv->format_name);
return -ENOTSUP;
}
return bs->drv->bdrv_amend_options(bs, opts, status_cb, cb_opaque, errp);
return bs->drv->bdrv_amend_options(bs, opts, status_cb,
cb_opaque, force, errp);
}
/*
+1 -1
View File
@@ -19,7 +19,7 @@ block-obj-$(CONFIG_WIN32) += file-win32.o win32-aio.o
block-obj-$(CONFIG_POSIX) += file-posix.o
block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o
block-obj-$(CONFIG_LINUX_IO_URING) += io_uring.o
block-obj-y += null.o mirror.o commit.o io.o create.o
block-obj-y += null.o mirror.o commit.o io.o create.o amend.o
block-obj-y += throttle-groups.o
block-obj-$(CONFIG_LINUX) += nvme.o
+113
View File
@@ -0,0 +1,113 @@
/*
* Block layer code related to image options amend
*
* Copyright (c) 2018 Kevin Wolf <kwolf@redhat.com>
* Copyright (c) 2020 Red Hat. Inc
*
* Heavily based on create.c
*
* 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 "block/block_int.h"
#include "qemu/job.h"
#include "qemu/main-loop.h"
#include "qapi/qapi-commands-block-core.h"
#include "qapi/qapi-visit-block-core.h"
#include "qapi/clone-visitor.h"
#include "qapi/error.h"
typedef struct BlockdevAmendJob {
Job common;
BlockdevAmendOptions *opts;
BlockDriverState *bs;
bool force;
} BlockdevAmendJob;
static int coroutine_fn blockdev_amend_run(Job *job, Error **errp)
{
BlockdevAmendJob *s = container_of(job, BlockdevAmendJob, common);
int ret;
job_progress_set_remaining(&s->common, 1);
ret = s->bs->drv->bdrv_co_amend(s->bs, s->opts, s->force, errp);
job_progress_update(&s->common, 1);
qapi_free_BlockdevAmendOptions(s->opts);
return ret;
}
static const JobDriver blockdev_amend_job_driver = {
.instance_size = sizeof(BlockdevAmendJob),
.job_type = JOB_TYPE_AMEND,
.run = blockdev_amend_run,
};
void qmp_x_blockdev_amend(const char *job_id,
const char *node_name,
BlockdevAmendOptions *options,
bool has_force,
bool force,
Error **errp)
{
BlockdevAmendJob *s;
const char *fmt = BlockdevDriver_str(options->driver);
BlockDriver *drv = bdrv_find_format(fmt);
BlockDriverState *bs = bdrv_find_node(node_name);
if (!drv) {
error_setg(errp, "Block driver '%s' not found or not supported", fmt);
return;
}
/*
* If the driver is in the schema, we know that it exists. But it may not
* be whitelisted.
*/
if (bdrv_uses_whitelist() && !bdrv_is_whitelisted(drv, false)) {
error_setg(errp, "Driver is not whitelisted");
return;
}
if (bs->drv != drv) {
error_setg(errp,
"x-blockdev-amend doesn't support changing the block driver");
return;
}
/* Error out if the driver doesn't support .bdrv_co_amend */
if (!drv->bdrv_co_amend) {
error_setg(errp, "Driver does not support x-blockdev-amend");
return;
}
/* Create the block job */
s = job_create(job_id, &blockdev_amend_job_driver, NULL,
bdrv_get_aio_context(bs), JOB_DEFAULT | JOB_MANUAL_DISMISS,
NULL, NULL, errp);
if (!s) {
return;
}
s->bs = bs,
s->opts = QAPI_CLONE(BlockdevAmendOptions, options),
s->force = has_force ? force : false;
job_start(&s->common);
}
+3 -1
View File
@@ -622,8 +622,10 @@ out:
* block_copy_task_run. If it fails, it means some task already failed
* for real reason, let's return first failure.
* Still, assert that we don't rewrite failure by success.
*
* Note: ret may be positive here because of block-status result.
*/
assert(ret == 0 || aio_task_pool_status(aio) < 0);
assert(ret >= 0 || aio_task_pool_status(aio) < 0);
ret = aio_task_pool_status(aio);
aio_task_pool_free(aio);
+190 -17
View File
@@ -37,6 +37,7 @@ typedef struct BlockCrypto BlockCrypto;
struct BlockCrypto {
QCryptoBlock *block;
bool updating_keys;
};
@@ -71,6 +72,24 @@ static ssize_t block_crypto_read_func(QCryptoBlock *block,
return ret;
}
static ssize_t block_crypto_write_func(QCryptoBlock *block,
size_t offset,
const uint8_t *buf,
size_t buflen,
void *opaque,
Error **errp)
{
BlockDriverState *bs = opaque;
ssize_t ret;
ret = bdrv_pwrite(bs->file, offset, buf, buflen);
if (ret < 0) {
error_setg_errno(errp, -ret, "Could not write encryption header");
return ret;
}
return ret;
}
struct BlockCryptoCreateData {
BlockBackend *blk;
@@ -79,12 +98,12 @@ struct BlockCryptoCreateData {
};
static ssize_t block_crypto_write_func(QCryptoBlock *block,
size_t offset,
const uint8_t *buf,
size_t buflen,
void *opaque,
Error **errp)
static ssize_t block_crypto_create_write_func(QCryptoBlock *block,
size_t offset,
const uint8_t *buf,
size_t buflen,
void *opaque,
Error **errp)
{
struct BlockCryptoCreateData *data = opaque;
ssize_t ret;
@@ -97,11 +116,10 @@ static ssize_t block_crypto_write_func(QCryptoBlock *block,
return ret;
}
static ssize_t block_crypto_init_func(QCryptoBlock *block,
size_t headerlen,
void *opaque,
Error **errp)
static ssize_t block_crypto_create_init_func(QCryptoBlock *block,
size_t headerlen,
void *opaque,
Error **errp)
{
struct BlockCryptoCreateData *data = opaque;
Error *local_error = NULL;
@@ -167,6 +185,19 @@ static QemuOptsList block_crypto_create_opts_luks = {
};
static QemuOptsList block_crypto_amend_opts_luks = {
.name = "crypto",
.head = QTAILQ_HEAD_INITIALIZER(block_crypto_create_opts_luks.head),
.desc = {
BLOCK_CRYPTO_OPT_DEF_LUKS_STATE(""),
BLOCK_CRYPTO_OPT_DEF_LUKS_KEYSLOT(""),
BLOCK_CRYPTO_OPT_DEF_LUKS_OLD_SECRET(""),
BLOCK_CRYPTO_OPT_DEF_LUKS_NEW_SECRET(""),
BLOCK_CRYPTO_OPT_DEF_LUKS_ITER_TIME(""),
{ /* end of list */ }
},
};
QCryptoBlockOpenOptions *
block_crypto_open_opts_init(QDict *opts, Error **errp)
{
@@ -202,6 +233,23 @@ block_crypto_create_opts_init(QDict *opts, Error **errp)
return ret;
}
QCryptoBlockAmendOptions *
block_crypto_amend_opts_init(QDict *opts, Error **errp)
{
Visitor *v;
QCryptoBlockAmendOptions *ret;
v = qobject_input_visitor_new_flat_confused(opts, errp);
if (!v) {
return NULL;
}
visit_type_QCryptoBlockAmendOptions(v, NULL, &ret, errp);
visit_free(v);
return ret;
}
static int block_crypto_open_generic(QCryptoBlockFormat format,
QemuOptsList *opts_spec,
@@ -296,8 +344,8 @@ static int block_crypto_co_create_generic(BlockDriverState *bs,
};
crypto = qcrypto_block_create(opts, NULL,
block_crypto_init_func,
block_crypto_write_func,
block_crypto_create_init_func,
block_crypto_create_write_func,
&data,
errp);
@@ -710,7 +758,6 @@ static int block_crypto_get_info_luks(BlockDriverState *bs,
return ret;
}
bdi->unallocated_blocks_are_zero = false;
bdi->cluster_size = subbdi.cluster_size;
return 0;
@@ -742,6 +789,131 @@ block_crypto_get_specific_info_luks(BlockDriverState *bs, Error **errp)
return spec_info;
}
static int
block_crypto_amend_options_generic_luks(BlockDriverState *bs,
QCryptoBlockAmendOptions *amend_options,
bool force,
Error **errp)
{
BlockCrypto *crypto = bs->opaque;
int ret;
assert(crypto);
assert(crypto->block);
/* apply for exclusive read/write permissions to the underlying file*/
crypto->updating_keys = true;
ret = bdrv_child_refresh_perms(bs, bs->file, errp);
if (ret) {
goto cleanup;
}
ret = qcrypto_block_amend_options(crypto->block,
block_crypto_read_func,
block_crypto_write_func,
bs,
amend_options,
force,
errp);
cleanup:
/* release exclusive read/write permissions to the underlying file*/
crypto->updating_keys = false;
bdrv_child_refresh_perms(bs, bs->file, errp);
return ret;
}
static int
block_crypto_amend_options_luks(BlockDriverState *bs,
QemuOpts *opts,
BlockDriverAmendStatusCB *status_cb,
void *cb_opaque,
bool force,
Error **errp)
{
BlockCrypto *crypto = bs->opaque;
QDict *cryptoopts = NULL;
QCryptoBlockAmendOptions *amend_options = NULL;
int ret = -EINVAL;
assert(crypto);
assert(crypto->block);
cryptoopts = qemu_opts_to_qdict(opts, NULL);
qdict_put_str(cryptoopts, "format", "luks");
amend_options = block_crypto_amend_opts_init(cryptoopts, errp);
qobject_unref(cryptoopts);
if (!amend_options) {
goto cleanup;
}
ret = block_crypto_amend_options_generic_luks(bs, amend_options,
force, errp);
cleanup:
qapi_free_QCryptoBlockAmendOptions(amend_options);
return ret;
}
static int
coroutine_fn block_crypto_co_amend_luks(BlockDriverState *bs,
BlockdevAmendOptions *opts,
bool force,
Error **errp)
{
QCryptoBlockAmendOptions amend_opts;
amend_opts = (QCryptoBlockAmendOptions) {
.format = Q_CRYPTO_BLOCK_FORMAT_LUKS,
.u.luks = *qapi_BlockdevAmendOptionsLUKS_base(&opts->u.luks),
};
return block_crypto_amend_options_generic_luks(bs, &amend_opts,
force, errp);
}
static void
block_crypto_child_perms(BlockDriverState *bs, BdrvChild *c,
const BdrvChildRole role,
BlockReopenQueue *reopen_queue,
uint64_t perm, uint64_t shared,
uint64_t *nperm, uint64_t *nshared)
{
BlockCrypto *crypto = bs->opaque;
bdrv_default_perms(bs, c, role, reopen_queue, perm, shared, nperm, nshared);
/*
* For backward compatibility, manually share the write
* and resize permission
*/
*nshared |= (BLK_PERM_WRITE | BLK_PERM_RESIZE);
/*
* Since we are not fully a format driver, don't always request
* the read/resize permission but only when explicitly
* requested
*/
*nperm &= ~(BLK_PERM_WRITE | BLK_PERM_RESIZE);
*nperm |= perm & (BLK_PERM_WRITE | BLK_PERM_RESIZE);
/*
* This driver doesn't modify LUKS metadata except
* when updating the encryption slots.
* Thus unlike a proper format driver we don't ask for
* shared write/read permission. However we need it
* when we are updating the keys, to ensure that only we
* have access to the device.
*
* Encryption update will set the crypto->updating_keys
* during that period and refresh permissions
*
*/
if (crypto->updating_keys) {
/* need exclusive write access for header update */
*nperm |= BLK_PERM_WRITE;
/* unshare read and write permission */
*nshared &= ~(BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE);
}
}
static const char *const block_crypto_strong_runtime_opts[] = {
BLOCK_CRYPTO_OPT_LUKS_KEY_SECRET,
@@ -754,13 +926,12 @@ static BlockDriver bdrv_crypto_luks = {
.bdrv_probe = block_crypto_probe_luks,
.bdrv_open = block_crypto_open_luks,
.bdrv_close = block_crypto_close,
/* This driver doesn't modify LUKS metadata except when creating image.
* Allow share-rw=on as a special case. */
.bdrv_child_perm = bdrv_default_perms,
.bdrv_child_perm = block_crypto_child_perms,
.bdrv_co_create = block_crypto_co_create_luks,
.bdrv_co_create_opts = block_crypto_co_create_opts_luks,
.bdrv_co_truncate = block_crypto_co_truncate,
.create_opts = &block_crypto_create_opts_luks,
.amend_opts = &block_crypto_amend_opts_luks,
.bdrv_reopen_prepare = block_crypto_reopen_prepare,
.bdrv_refresh_limits = block_crypto_refresh_limits,
@@ -770,6 +941,8 @@ static BlockDriver bdrv_crypto_luks = {
.bdrv_measure = block_crypto_measure,
.bdrv_get_info = block_crypto_get_info_luks,
.bdrv_get_specific_info = block_crypto_get_specific_info_luks,
.bdrv_amend_options = block_crypto_amend_options_luks,
.bdrv_co_amend = block_crypto_co_amend_luks,
.is_format = true,
+37
View File
@@ -41,6 +41,11 @@
#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_LUKS_KEYSLOT "keyslot"
#define BLOCK_CRYPTO_OPT_LUKS_STATE "state"
#define BLOCK_CRYPTO_OPT_LUKS_OLD_SECRET "old-secret"
#define BLOCK_CRYPTO_OPT_LUKS_NEW_SECRET "new-secret"
#define BLOCK_CRYPTO_OPT_DEF_LUKS_KEY_SECRET(prefix) \
BLOCK_CRYPTO_OPT_DEF_KEY_SECRET(prefix, \
@@ -88,9 +93,41 @@
.help = "Time to spend in PBKDF in milliseconds", \
}
#define BLOCK_CRYPTO_OPT_DEF_LUKS_STATE(prefix) \
{ \
.name = prefix BLOCK_CRYPTO_OPT_LUKS_STATE, \
.type = QEMU_OPT_STRING, \
.help = "Select new state of affected keyslots (active/inactive)",\
}
#define BLOCK_CRYPTO_OPT_DEF_LUKS_KEYSLOT(prefix) \
{ \
.name = prefix BLOCK_CRYPTO_OPT_LUKS_KEYSLOT, \
.type = QEMU_OPT_NUMBER, \
.help = "Select a single keyslot to modify explicitly",\
}
#define BLOCK_CRYPTO_OPT_DEF_LUKS_OLD_SECRET(prefix) \
{ \
.name = prefix BLOCK_CRYPTO_OPT_LUKS_OLD_SECRET, \
.type = QEMU_OPT_STRING, \
.help = "Select all keyslots that match this password", \
}
#define BLOCK_CRYPTO_OPT_DEF_LUKS_NEW_SECRET(prefix) \
{ \
.name = prefix BLOCK_CRYPTO_OPT_LUKS_NEW_SECRET, \
.type = QEMU_OPT_STRING, \
.help = "New secret to set in the matching keyslots. " \
"Empty string to erase", \
}
QCryptoBlockCreateOptions *
block_crypto_create_opts_init(QDict *opts, Error **errp);
QCryptoBlockAmendOptions *
block_crypto_amend_opts_init(QDict *opts, Error **errp);
QCryptoBlockOpenOptions *
block_crypto_open_opts_init(QDict *opts, Error **errp);
-3
View File
@@ -2878,9 +2878,6 @@ static int coroutine_fn raw_co_pwrite_zeroes(
static int raw_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
{
BDRVRawState *s = bs->opaque;
bdi->unallocated_blocks_are_zero = s->discard_zeroes;
return 0;
}
+4 -4
View File
@@ -2406,16 +2406,16 @@ static int coroutine_fn bdrv_co_block_status(BlockDriverState *bs,
if (ret & (BDRV_BLOCK_DATA | BDRV_BLOCK_ZERO)) {
ret |= BDRV_BLOCK_ALLOCATED;
} else if (want_zero) {
if (bdrv_unallocated_blocks_are_zero(bs)) {
ret |= BDRV_BLOCK_ZERO;
} else if (bs->backing) {
} else if (want_zero && bs->drv->supports_backing) {
if (bs->backing) {
BlockDriverState *bs2 = bs->backing->bs;
int64_t size2 = bdrv_getlength(bs2);
if (size2 >= 0 && offset >= size2) {
ret |= BDRV_BLOCK_ZERO;
}
} else {
ret |= BDRV_BLOCK_ZERO;
}
}
-1
View File
@@ -2163,7 +2163,6 @@ static int coroutine_fn iscsi_co_truncate(BlockDriverState *bs, int64_t offset,
static int iscsi_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
{
IscsiLun *iscsilun = bs->opaque;
bdi->unallocated_blocks_are_zero = iscsilun->lbprz;
bdi->cluster_size = iscsilun->cluster_size;
return 0;
}
+205 -149
View File
@@ -176,6 +176,19 @@ static ssize_t qcow2_crypto_hdr_write_func(QCryptoBlock *block, size_t offset,
return ret;
}
static QDict*
qcow2_extract_crypto_opts(QemuOpts *opts, const char *fmt, Error **errp)
{
QDict *cryptoopts_qdict;
QDict *opts_qdict;
/* Extract "encrypt." options into a qdict */
opts_qdict = qemu_opts_to_qdict(opts, NULL);
qdict_extract_subqdict(opts_qdict, &cryptoopts_qdict, "encrypt.");
qobject_unref(opts_qdict);
qdict_put_str(cryptoopts_qdict, "format", fmt);
return cryptoopts_qdict;
}
/*
* read qcow2 extension and fill bs
@@ -3042,17 +3055,6 @@ 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,
QCryptoBlockCreateOptions *cryptoopts,
Error **errp)
@@ -4239,8 +4241,8 @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset,
old_file_size = ROUND_UP(old_file_size, s->cluster_size);
}
nb_new_data_clusters = DIV_ROUND_UP(offset - old_length,
s->cluster_size);
nb_new_data_clusters = (ROUND_UP(offset, s->cluster_size) -
start_of_cluster(s, old_length)) >> s->cluster_bits;
/* This is an overestimation; we will not actually allocate space for
* these in the file but just make sure the new refcount structures are
@@ -4317,10 +4319,21 @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset,
int64_t nb_clusters = MIN(
nb_new_data_clusters,
s->l2_slice_size - offset_to_l2_slice_index(s, guest_offset));
QCowL2Meta allocation = {
unsigned cow_start_length = offset_into_cluster(s, guest_offset);
QCowL2Meta allocation;
guest_offset = start_of_cluster(s, guest_offset);
allocation = (QCowL2Meta) {
.offset = guest_offset,
.alloc_offset = host_offset,
.nb_clusters = nb_clusters,
.cow_start = {
.offset = 0,
.nb_bytes = cow_start_length,
},
.cow_end = {
.offset = nb_clusters << s->cluster_bits,
.nb_bytes = 0,
},
};
qemu_co_queue_init(&allocation.dependent_requests);
@@ -4860,16 +4873,9 @@ static BlockMeasureInfo *qcow2_measure(QemuOpts *opts, BlockDriverState *in_bs,
if (has_luks) {
g_autoptr(QCryptoBlockCreateOptions) create_opts = NULL;
QDict *opts_qdict;
QDict *cryptoopts;
QDict *cryptoopts = qcow2_extract_crypto_opts(opts, "luks", errp);
size_t headerlen;
opts_qdict = qemu_opts_to_qdict(opts, NULL);
qdict_extract_subqdict(opts_qdict, &cryptoopts, "encrypt.");
qobject_unref(opts_qdict);
qdict_put_str(cryptoopts, "format", "luks");
create_opts = block_crypto_create_opts_init(cryptoopts, errp);
qobject_unref(cryptoopts);
if (!create_opts) {
@@ -4981,7 +4987,6 @@ err:
static int qcow2_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
{
BDRVQcow2State *s = bs->opaque;
bdi->unallocated_blocks_are_zero = true;
bdi->cluster_size = s->cluster_size;
bdi->vm_state_offset = qcow2_vm_state_offset(s);
return 0;
@@ -5273,6 +5278,7 @@ typedef enum Qcow2AmendOperation {
QCOW2_NO_OPERATION = 0,
QCOW2_UPGRADING,
QCOW2_UPDATING_ENCRYPTION,
QCOW2_CHANGING_REFCOUNT_ORDER,
QCOW2_DOWNGRADING,
} Qcow2AmendOperation;
@@ -5340,6 +5346,7 @@ static void qcow2_amend_helper_cb(BlockDriverState *bs,
static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts,
BlockDriverAmendStatusCB *status_cb,
void *cb_opaque,
bool force,
Error **errp)
{
BDRVQcow2State *s = bs->opaque;
@@ -5349,13 +5356,11 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts,
bool lazy_refcounts = s->use_lazy_refcounts;
bool data_file_raw = data_file_is_raw(bs);
const char *compat = NULL;
uint64_t cluster_size = s->cluster_size;
bool encrypt;
int encformat;
int refcount_bits = s->refcount_bits;
int ret;
QemuOptDesc *desc = opts->list->desc;
Qcow2AmendHelperCBInfo helper_cb_info;
bool encryption_update = false;
while (desc && desc->name) {
if (!qemu_opt_find(opts, desc->name)) {
@@ -5376,44 +5381,24 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts,
error_setg(errp, "Unknown compatibility level %s", compat);
return -EINVAL;
}
} else if (!strcmp(desc->name, BLOCK_OPT_PREALLOC)) {
error_setg(errp, "Cannot change preallocation mode");
return -ENOTSUP;
} else if (!strcmp(desc->name, BLOCK_OPT_SIZE)) {
new_size = qemu_opt_get_size(opts, BLOCK_OPT_SIZE, 0);
} else if (!strcmp(desc->name, BLOCK_OPT_BACKING_FILE)) {
backing_file = qemu_opt_get(opts, BLOCK_OPT_BACKING_FILE);
} else if (!strcmp(desc->name, BLOCK_OPT_BACKING_FMT)) {
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->crypto);
if (encrypt != !!s->crypto) {
error_setg(errp,
"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_setg(errp,
"Changing the encryption format is not supported");
return -ENOTSUP;
}
} else if (g_str_has_prefix(desc->name, "encrypt.")) {
error_setg(errp,
"Changing the encryption parameters 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);
if (cluster_size != s->cluster_size) {
error_setg(errp, "Changing the cluster size is not supported");
if (!s->crypto) {
error_setg(errp,
"Can't amend encryption options - encryption not present");
return -EINVAL;
}
if (s->crypt_method_header != QCOW_CRYPT_LUKS) {
error_setg(errp,
"Only LUKS encryption options can be amended");
return -ENOTSUP;
}
encryption_update = true;
} else if (!strcmp(desc->name, BLOCK_OPT_LAZY_REFCOUNTS)) {
lazy_refcounts = qemu_opt_get_bool(opts, BLOCK_OPT_LAZY_REFCOUNTS,
lazy_refcounts);
@@ -5443,22 +5428,6 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts,
"images");
return -EINVAL;
}
} else if (!strcmp(desc->name, BLOCK_OPT_COMPRESSION_TYPE)) {
const char *ct_name =
qemu_opt_get(opts, BLOCK_OPT_COMPRESSION_TYPE);
int compression_type =
qapi_enum_parse(&Qcow2CompressionType_lookup, ct_name, -1,
NULL);
if (compression_type == -1) {
error_setg(errp, "Unknown compression type: %s", ct_name);
return -ENOTSUP;
}
if (compression_type != s->compression_type) {
error_setg(errp, "Changing the compression type "
"is not supported");
return -ENOTSUP;
}
} else {
/* if this point is reached, this probably means a new option was
* added without having it covered here */
@@ -5472,7 +5441,8 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts,
.original_status_cb = status_cb,
.original_cb_opaque = cb_opaque,
.total_operations = (new_version != old_version)
+ (s->refcount_bits != refcount_bits)
+ (s->refcount_bits != refcount_bits) +
(encryption_update == true)
};
/* Upgrade first (some features may require compat=1.1) */
@@ -5485,6 +5455,33 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts,
}
}
if (encryption_update) {
QDict *amend_opts_dict;
QCryptoBlockAmendOptions *amend_opts;
helper_cb_info.current_operation = QCOW2_UPDATING_ENCRYPTION;
amend_opts_dict = qcow2_extract_crypto_opts(opts, "luks", errp);
if (!amend_opts_dict) {
return -EINVAL;
}
amend_opts = block_crypto_amend_opts_init(amend_opts_dict, errp);
qobject_unref(amend_opts_dict);
if (!amend_opts) {
return -EINVAL;
}
ret = qcrypto_block_amend_options(s->crypto,
qcow2_crypto_hdr_read_func,
qcow2_crypto_hdr_write_func,
bs,
amend_opts,
force,
errp);
qapi_free_QCryptoBlockAmendOptions(amend_opts);
if (ret < 0) {
return ret;
}
}
if (s->refcount_bits != refcount_bits) {
int refcount_order = ctz32(refcount_bits);
@@ -5598,6 +5595,44 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts,
return 0;
}
static int coroutine_fn qcow2_co_amend(BlockDriverState *bs,
BlockdevAmendOptions *opts,
bool force,
Error **errp)
{
BlockdevAmendOptionsQcow2 *qopts = &opts->u.qcow2;
BDRVQcow2State *s = bs->opaque;
int ret = 0;
if (qopts->has_encrypt) {
if (!s->crypto) {
error_setg(errp, "image is not encrypted, can't amend");
return -EOPNOTSUPP;
}
if (qopts->encrypt->format != Q_CRYPTO_BLOCK_FORMAT_LUKS) {
error_setg(errp,
"Amend can't be used to change the qcow2 encryption format");
return -EOPNOTSUPP;
}
if (s->crypt_method_header != QCOW_CRYPT_LUKS) {
error_setg(errp,
"Only LUKS encryption options can be amended for qcow2 with blockdev-amend");
return -EOPNOTSUPP;
}
ret = qcrypto_block_amend_options(s->crypto,
qcow2_crypto_hdr_read_func,
qcow2_crypto_hdr_write_func,
bs,
qopts->encrypt,
force,
errp);
}
return ret;
}
/*
* If offset or size are negative, respectively, they will not be included in
* the BLOCK_IMAGE_CORRUPTED event emitted.
@@ -5648,89 +5683,108 @@ void qcow2_signal_corruption(BlockDriverState *bs, bool fatal, int64_t offset,
s->signaled_corruption = true;
}
#define QCOW_COMMON_OPTIONS \
{ \
.name = BLOCK_OPT_SIZE, \
.type = QEMU_OPT_SIZE, \
.help = "Virtual disk size" \
}, \
{ \
.name = BLOCK_OPT_COMPAT_LEVEL, \
.type = QEMU_OPT_STRING, \
.help = "Compatibility level (v2 [0.10] or v3 [1.1])" \
}, \
{ \
.name = BLOCK_OPT_BACKING_FILE, \
.type = QEMU_OPT_STRING, \
.help = "File name of a base image" \
}, \
{ \
.name = BLOCK_OPT_BACKING_FMT, \
.type = QEMU_OPT_STRING, \
.help = "Image format of the base image" \
}, \
{ \
.name = BLOCK_OPT_DATA_FILE, \
.type = QEMU_OPT_STRING, \
.help = "File name of an external data file" \
}, \
{ \
.name = BLOCK_OPT_DATA_FILE_RAW, \
.type = QEMU_OPT_BOOL, \
.help = "The external data file must stay valid " \
"as a raw image" \
}, \
{ \
.name = BLOCK_OPT_LAZY_REFCOUNTS, \
.type = QEMU_OPT_BOOL, \
.help = "Postpone refcount updates", \
.def_value_str = "off" \
}, \
{ \
.name = BLOCK_OPT_REFCOUNT_BITS, \
.type = QEMU_OPT_NUMBER, \
.help = "Width of a reference count entry in bits", \
.def_value_str = "16" \
}
static QemuOptsList qcow2_create_opts = {
.name = "qcow2-create-opts",
.head = QTAILQ_HEAD_INITIALIZER(qcow2_create_opts.head),
.desc = {
{
.name = BLOCK_OPT_SIZE,
.type = QEMU_OPT_SIZE,
.help = "Virtual disk size"
{ \
.name = BLOCK_OPT_ENCRYPT, \
.type = QEMU_OPT_BOOL, \
.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', 'luks'", \
}, \
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, \
.help = "qcow2 cluster size", \
.def_value_str = stringify(DEFAULT_CLUSTER_SIZE) \
}, \
{ \
.name = BLOCK_OPT_PREALLOC, \
.type = QEMU_OPT_STRING, \
.help = "Preallocation mode (allowed values: off, " \
"metadata, falloc, full)" \
}, \
{ \
.name = BLOCK_OPT_COMPRESSION_TYPE, \
.type = QEMU_OPT_STRING, \
.help = "Compression method used for image cluster " \
"compression", \
.def_value_str = "zlib" \
},
{
.name = BLOCK_OPT_COMPAT_LEVEL,
.type = QEMU_OPT_STRING,
.help = "Compatibility level (v2 [0.10] or v3 [1.1])"
},
{
.name = BLOCK_OPT_BACKING_FILE,
.type = QEMU_OPT_STRING,
.help = "File name of a base image"
},
{
.name = BLOCK_OPT_BACKING_FMT,
.type = QEMU_OPT_STRING,
.help = "Image format of the base image"
},
{
.name = BLOCK_OPT_DATA_FILE,
.type = QEMU_OPT_STRING,
.help = "File name of an external data file"
},
{
.name = BLOCK_OPT_DATA_FILE_RAW,
.type = QEMU_OPT_BOOL,
.help = "The external data file must stay valid as a raw image"
},
{
.name = BLOCK_OPT_ENCRYPT,
.type = QEMU_OPT_BOOL,
.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', 'luks'",
},
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."),
QCOW_COMMON_OPTIONS,
{ /* end of list */ }
}
};
static QemuOptsList qcow2_amend_opts = {
.name = "qcow2-amend-opts",
.head = QTAILQ_HEAD_INITIALIZER(qcow2_amend_opts.head),
.desc = {
BLOCK_CRYPTO_OPT_DEF_LUKS_STATE("encrypt."),
BLOCK_CRYPTO_OPT_DEF_LUKS_KEYSLOT("encrypt."),
BLOCK_CRYPTO_OPT_DEF_LUKS_OLD_SECRET("encrypt."),
BLOCK_CRYPTO_OPT_DEF_LUKS_NEW_SECRET("encrypt."),
BLOCK_CRYPTO_OPT_DEF_LUKS_ITER_TIME("encrypt."),
{
.name = BLOCK_OPT_CLUSTER_SIZE,
.type = QEMU_OPT_SIZE,
.help = "qcow2 cluster size",
.def_value_str = stringify(DEFAULT_CLUSTER_SIZE)
},
{
.name = BLOCK_OPT_PREALLOC,
.type = QEMU_OPT_STRING,
.help = "Preallocation mode (allowed values: off, metadata, "
"falloc, full)"
},
{
.name = BLOCK_OPT_LAZY_REFCOUNTS,
.type = QEMU_OPT_BOOL,
.help = "Postpone refcount updates",
.def_value_str = "off"
},
{
.name = BLOCK_OPT_REFCOUNT_BITS,
.type = QEMU_OPT_NUMBER,
.help = "Width of a reference count entry in bits",
.def_value_str = "16"
},
{
.name = BLOCK_OPT_COMPRESSION_TYPE,
.type = QEMU_OPT_STRING,
.help = "Compression method used for image cluster compression",
.def_value_str = "zlib"
},
QCOW_COMMON_OPTIONS,
{ /* end of list */ }
}
};
@@ -5791,10 +5845,12 @@ BlockDriver bdrv_qcow2 = {
.bdrv_inactivate = qcow2_inactivate,
.create_opts = &qcow2_create_opts,
.amend_opts = &qcow2_amend_opts,
.strong_runtime_opts = qcow2_strong_runtime_opts,
.mutable_opts = mutable_opts,
.bdrv_co_check = qcow2_co_check,
.bdrv_amend_options = qcow2_amend_options,
.bdrv_co_amend = qcow2_co_amend,
.bdrv_detach_aio_context = qcow2_detach_aio_context,
.bdrv_attach_aio_context = qcow2_attach_aio_context,
+6 -59
View File
@@ -849,56 +849,18 @@ static BDRVQEDState *acb_to_s(QEDAIOCB *acb)
* @s: QED state
* @pos: Byte position in device
* @qiov: Destination I/O vector
* @backing_qiov: Possibly shortened copy of qiov, to be allocated here
* @cb: Completion function
* @opaque: User data for completion function
*
* This function reads qiov->size bytes starting at pos from the backing file.
* If there is no backing file then zeroes are read.
*/
static int coroutine_fn qed_read_backing_file(BDRVQEDState *s, uint64_t pos,
QEMUIOVector *qiov,
QEMUIOVector **backing_qiov)
QEMUIOVector *qiov)
{
uint64_t backing_length = 0;
size_t size;
int ret;
/* If there is a backing file, get its length. Treat the absence of a
* backing file like a zero length backing file.
*/
if (s->bs->backing) {
int64_t l = bdrv_getlength(s->bs->backing->bs);
if (l < 0) {
return l;
}
backing_length = l;
}
/* Zero all sectors if reading beyond the end of the backing file */
if (pos >= backing_length ||
pos + qiov->size > backing_length) {
qemu_iovec_memset(qiov, 0, 0, qiov->size);
}
/* Complete now if there are no backing file sectors to read */
if (pos >= backing_length) {
return 0;
}
/* If the read straddles the end of the backing file, shorten it */
size = MIN((uint64_t)backing_length - pos, qiov->size);
assert(*backing_qiov == NULL);
*backing_qiov = g_new(QEMUIOVector, 1);
qemu_iovec_init(*backing_qiov, qiov->niov);
qemu_iovec_concat(*backing_qiov, qiov, 0, size);
BLKDBG_EVENT(s->bs->file, BLKDBG_READ_BACKING_AIO);
ret = bdrv_co_preadv(s->bs->backing, pos, size, *backing_qiov, 0);
if (ret < 0) {
return ret;
BLKDBG_EVENT(s->bs->file, BLKDBG_READ_BACKING_AIO);
return bdrv_co_preadv(s->bs->backing, pos, qiov->size, qiov, 0);
}
qemu_iovec_memset(qiov, 0, 0, qiov->size);
return 0;
}
@@ -915,7 +877,6 @@ static int coroutine_fn qed_copy_from_backing_file(BDRVQEDState *s,
uint64_t offset)
{
QEMUIOVector qiov;
QEMUIOVector *backing_qiov = NULL;
int ret;
/* Skip copy entirely if there is no work to do */
@@ -925,13 +886,7 @@ static int coroutine_fn qed_copy_from_backing_file(BDRVQEDState *s,
qemu_iovec_init_buf(&qiov, qemu_blockalign(s->bs, len), len);
ret = qed_read_backing_file(s, pos, &qiov, &backing_qiov);
if (backing_qiov) {
qemu_iovec_destroy(backing_qiov);
g_free(backing_qiov);
backing_qiov = NULL;
}
ret = qed_read_backing_file(s, pos, &qiov);
if (ret) {
goto out;
@@ -1339,8 +1294,7 @@ static int coroutine_fn qed_aio_read_data(void *opaque, int ret,
qemu_iovec_memset(&acb->cur_qiov, 0, 0, acb->cur_qiov.size);
r = 0;
} else if (ret != QED_CLUSTER_FOUND) {
r = qed_read_backing_file(s, acb->cur_pos, &acb->cur_qiov,
&acb->backing_qiov);
r = qed_read_backing_file(s, acb->cur_pos, &acb->cur_qiov);
} else {
BLKDBG_EVENT(bs->file, BLKDBG_READ_AIO);
r = bdrv_co_preadv(bs->file, offset, acb->cur_qiov.size,
@@ -1365,12 +1319,6 @@ static int coroutine_fn qed_aio_next_io(QEDAIOCB *acb)
while (1) {
trace_qed_aio_next_io(s, acb, 0, acb->cur_pos + acb->cur_qiov.size);
if (acb->backing_qiov) {
qemu_iovec_destroy(acb->backing_qiov);
g_free(acb->backing_qiov);
acb->backing_qiov = NULL;
}
acb->qiov_offset += acb->cur_qiov.size;
acb->cur_pos += acb->cur_qiov.size;
qemu_iovec_reset(&acb->cur_qiov);
@@ -1514,7 +1462,6 @@ static int bdrv_qed_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
memset(bdi, 0, sizeof(*bdi));
bdi->cluster_size = s->header.cluster_size;
bdi->is_dirty = s->header.features & QED_F_NEED_CHECK;
bdi->unallocated_blocks_are_zero = true;
return 0;
}
-1
View File
@@ -140,7 +140,6 @@ typedef struct QEDAIOCB {
/* Current cluster scatter-gather list */
QEMUIOVector cur_qiov;
QEMUIOVector *backing_qiov;
uint64_t cur_pos; /* position on block device, in bytes */
uint64_t cur_cluster; /* cluster offset in image file */
unsigned int cur_nclusters; /* number of clusters being accessed */
+1 -2
View File
@@ -334,7 +334,6 @@ static int vdi_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
logout("\n");
bdi->cluster_size = s->block_size;
bdi->vm_state_offset = 0;
bdi->unallocated_blocks_are_zero = true;
return 0;
}
@@ -536,7 +535,7 @@ static int coroutine_fn vdi_co_block_status(BlockDriverState *bs,
*pnum = MIN(s->block_size - index_in_block, bytes);
result = VDI_IS_ALLOCATED(bmap_entry);
if (!result) {
return 0;
return BDRV_BLOCK_ZERO;
}
*map = s->header.offset_data + (uint64_t)bmap_entry * s->block_size +
-3
View File
@@ -1164,9 +1164,6 @@ static int vhdx_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
bdi->cluster_size = s->block_size;
bdi->unallocated_blocks_are_zero =
(s->params.data_bits & VHDX_PARAMS_HAS_PARENT) == 0;
return 0;
}
+1 -2
View File
@@ -606,7 +606,6 @@ static int vpc_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
bdi->cluster_size = s->block_size;
}
bdi->unallocated_blocks_are_zero = true;
return 0;
}
@@ -745,7 +744,7 @@ static int coroutine_fn vpc_co_block_status(BlockDriverState *bs,
image_offset = get_image_offset(bs, offset, false, NULL);
allocated = (image_offset != -1);
*pnum = 0;
ret = 0;
ret = BDRV_BLOCK_ZERO;
do {
/* All sectors in a block are contiguous (without using the bitmap) */
+412 -4
View File
File diff suppressed because it is too large Load Diff
+29
View File
@@ -150,6 +150,35 @@ qcrypto_block_calculate_payload_offset(QCryptoBlockCreateOptions *create_opts,
return crypto != NULL;
}
int qcrypto_block_amend_options(QCryptoBlock *block,
QCryptoBlockReadFunc readfunc,
QCryptoBlockWriteFunc writefunc,
void *opaque,
QCryptoBlockAmendOptions *options,
bool force,
Error **errp)
{
if (options->format != block->format) {
error_setg(errp,
"Cannot amend encryption format");
return -1;
}
if (!block->driver->amend) {
error_setg(errp,
"Crypto format %s doesn't support format options amendment",
QCryptoBlockFormat_str(block->format));
return -1;
}
return block->driver->amend(block,
readfunc,
writefunc,
opaque,
options,
force,
errp);
}
QCryptoBlockInfo *qcrypto_block_get_info(QCryptoBlock *block,
Error **errp)
+8
View File
@@ -62,6 +62,14 @@ struct QCryptoBlockDriver {
void *opaque,
Error **errp);
int (*amend)(QCryptoBlock *block,
QCryptoBlockReadFunc readfunc,
QCryptoBlockWriteFunc writefunc,
void *opaque,
QCryptoBlockAmendOptions *options,
bool force,
Error **errp);
int (*get_info)(QCryptoBlock *block,
QCryptoBlockInfo *info,
Error **errp);
+4 -1
View File
@@ -253,11 +253,14 @@ Command description:
.. program:: qemu-img-commands
.. option:: amend [--object OBJECTDEF] [--image-opts] [-p] [-q] [-f FMT] [-t CACHE] -o OPTIONS FILENAME
.. option:: amend [--object OBJECTDEF] [--image-opts] [-p] [-q] [-f FMT] [-t CACHE] [--force] -o OPTIONS FILENAME
Amends the image format specific *OPTIONS* for the image file
*FILENAME*. Not all file formats support this operation.
--force allows some unsafe operations. Currently for -f luks, it allows to
erase the last encryption key, and to overwrite an active encryption key.
.. option:: bench [-c COUNT] [-d DEPTH] [-f FMT] [--flush-interval=FLUSH_INTERVAL] [-i AIO] [-n] [--no-drain] [-o OFFSET] [--pattern=PATTERN] [-q] [-s BUFFER_SIZE] [-S STEP_SIZE] [-t CACHE] [-w] [-U] FILENAME
Run a simple sequential I/O benchmark on the specified image. If ``-w`` is
+1 -6
View File
@@ -21,11 +21,6 @@ typedef struct BlockDriverInfo {
/* offset at which the VM state can be saved (0 if not possible) */
int64_t vm_state_offset;
bool is_dirty;
/*
* True if unallocated blocks read back as zeroes. This is equivalent
* to the LBPRZ flag in the SCSI logical block provisioning page.
*/
bool unallocated_blocks_are_zero;
/*
* True if this block driver only supports compressed writes
*/
@@ -450,6 +445,7 @@ typedef void BlockDriverAmendStatusCB(BlockDriverState *bs, int64_t offset,
int64_t total_work_size, void *opaque);
int bdrv_amend_options(BlockDriverState *bs_new, QemuOpts *opts,
BlockDriverAmendStatusCB *status_cb, void *cb_opaque,
bool force,
Error **errp);
/* check if a named node can be replaced when doing drive-mirror */
@@ -488,7 +484,6 @@ int bdrv_pdiscard(BdrvChild *child, int64_t offset, int64_t bytes);
int bdrv_co_pdiscard(BdrvChild *child, int64_t offset, int64_t bytes);
int bdrv_has_zero_init_1(BlockDriverState *bs);
int bdrv_has_zero_init(BlockDriverState *bs);
bool bdrv_unallocated_blocks_are_zero(BlockDriverState *bs);
bool bdrv_can_write_zeroes_with_unmap(BlockDriverState *bs);
int bdrv_block_status(BlockDriverState *bs, int64_t offset,
int64_t bytes, int64_t *pnum, int64_t *map,

Some files were not shown because too many files have changed in this diff Show More