Commit eb2c66b1 authored by Peter Maydell's avatar Peter Maydell
Browse files

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: default avatarPeter Maydell <peter.maydell@linaro.org>
parents c8eaf81f 365fed51
Loading
Loading
Loading
Loading
+3 −16
Original line number Diff line number Diff line
@@ -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
Original line number Diff line number Diff line
@@ -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

block/amend.c

0 → 100644
+113 −0
Original line number Diff line number Diff line
/*
 * 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
Original line number Diff line number Diff line
@@ -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
Original line number Diff line number Diff line
@@ -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,7 +98,7 @@ struct BlockCryptoCreateData {
};


static ssize_t block_crypto_write_func(QCryptoBlock *block,
static ssize_t block_crypto_create_write_func(QCryptoBlock *block,
                                              size_t offset,
                                              const uint8_t *buf,
                                              size_t buflen,
@@ -97,8 +116,7 @@ static ssize_t block_crypto_write_func(QCryptoBlock *block,
    return ret;
}


static ssize_t block_crypto_init_func(QCryptoBlock *block,
static ssize_t block_crypto_create_init_func(QCryptoBlock *block,
                                             size_t headerlen,
                                             void *opaque,
                                             Error **errp)
@@ -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,

Loading