Commit 12c06d6f authored by Peter Maydell's avatar Peter Maydell
Browse files

Merge remote-tracking branch 'remotes/kevin/tags/for-upstream' into staging



Block layer patches

# gpg: Signature made Fri 09 Mar 2018 15:09:20 GMT
# gpg:                using RSA key 7F09B272C88F2FD6
# gpg: Good signature from "Kevin Wolf <kwolf@redhat.com>"
# Primary key fingerprint: DC3D EB15 9A9A F95D 3D74  56FE 7F09 B272 C88F 2FD6

* remotes/kevin/tags/for-upstream: (56 commits)
  qemu-iotests: fix 203 migration completion race
  iotests: Tweak 030 in order to trigger a race condition with parallel jobs
  iotests: Skip test for ENOMEM error
  iotests: Mark all tests executable
  iotests: Test creating overlay when guest running
  qemu-iotests: Test ssh image creation over QMP
  qemu-iotests: Test qcow2 over file image creation with QMP
  block: Fail bdrv_truncate() with negative size
  file-posix: Fix no-op bdrv_truncate() with falloc preallocation
  ssh: Support .bdrv_co_create
  ssh: Pass BlockdevOptionsSsh to connect_to_ssh()
  ssh: QAPIfy host-key-check option
  ssh: Use QAPI BlockdevOptionsSsh object
  sheepdog: Support .bdrv_co_create
  sheepdog: QAPIfy "redundancy" create option
  nfs: Support .bdrv_co_create
  nfs: Use QAPI options in nfs_client_open()
  rbd: Use qemu_rbd_connect() in qemu_rbd_do_create()
  rbd: Assign s->snap/image_name in qemu_rbd_open()
  rbd: Support .bdrv_co_create
  ...

Signed-off-by: default avatarPeter Maydell <peter.maydell@linaro.org>
parents 20f59d12 a1be5921
Loading
Loading
Loading
Loading
+130 −8
Original line number Diff line number Diff line
@@ -34,6 +34,8 @@
#include "qapi/qmp/qdict.h"
#include "qapi/qmp/qjson.h"
#include "qapi/qmp/qstring.h"
#include "qapi/qobject-output-visitor.h"
#include "qapi/qapi-visit-block-core.h"
#include "sysemu/block-backend.h"
#include "sysemu/sysemu.h"
#include "qemu/notify.h"
@@ -368,7 +370,7 @@ BlockDriver *bdrv_find_format(const char *format_name)
    return bdrv_do_find_format(format_name);
}

static int bdrv_is_whitelisted(BlockDriver *drv, bool read_only)
int bdrv_is_whitelisted(BlockDriver *drv, bool read_only)
{
    static const char *whitelist_rw[] = {
        CONFIG_BDRV_RW_WHITELIST
@@ -2406,6 +2408,51 @@ BdrvChild *bdrv_open_child(const char *filename,
    return c;
}

/* TODO Future callers may need to specify parent/child_role in order for
 * option inheritance to work. Existing callers use it for the root node. */
BlockDriverState *bdrv_open_blockdev_ref(BlockdevRef *ref, Error **errp)
{
    BlockDriverState *bs = NULL;
    Error *local_err = NULL;
    QObject *obj = NULL;
    QDict *qdict = NULL;
    const char *reference = NULL;
    Visitor *v = NULL;

    if (ref->type == QTYPE_QSTRING) {
        reference = ref->u.reference;
    } else {
        BlockdevOptions *options = &ref->u.definition;
        assert(ref->type == QTYPE_QDICT);

        v = qobject_output_visitor_new(&obj);
        visit_type_BlockdevOptions(v, NULL, &options, &local_err);
        if (local_err) {
            error_propagate(errp, local_err);
            goto fail;
        }
        visit_complete(v, &obj);

        qdict = qobject_to_qdict(obj);
        qdict_flatten(qdict);

        /* bdrv_open_inherit() defaults to the values in bdrv_flags (for
         * compatibility with other callers) rather than what we want as the
         * real defaults. Apply the defaults here instead. */
        qdict_set_default_str(qdict, BDRV_OPT_CACHE_DIRECT, "off");
        qdict_set_default_str(qdict, BDRV_OPT_CACHE_NO_FLUSH, "off");
        qdict_set_default_str(qdict, BDRV_OPT_READ_ONLY, "off");
    }

    bs = bdrv_open_inherit(NULL, reference, qdict, 0, NULL, NULL, errp);
    obj = NULL;

fail:
    qobject_decref(obj);
    visit_free(v);
    return bs;
}

static BlockDriverState *bdrv_append_temp_snapshot(BlockDriverState *bs,
                                                   int flags,
                                                   QDict *snapshot_options,
@@ -3455,17 +3502,54 @@ static void bdrv_delete(BlockDriverState *bs)
 * free of errors) or -errno when an internal error occurred. The results of the
 * check are stored in res.
 */
int bdrv_check(BlockDriverState *bs, BdrvCheckResult *res, BdrvCheckMode fix)
static int coroutine_fn bdrv_co_check(BlockDriverState *bs,
                                      BdrvCheckResult *res, BdrvCheckMode fix)
{
    if (bs->drv == NULL) {
        return -ENOMEDIUM;
    }
    if (bs->drv->bdrv_check == NULL) {
    if (bs->drv->bdrv_co_check == NULL) {
        return -ENOTSUP;
    }

    memset(res, 0, sizeof(*res));
    return bs->drv->bdrv_check(bs, res, fix);
    return bs->drv->bdrv_co_check(bs, res, fix);
}

typedef struct CheckCo {
    BlockDriverState *bs;
    BdrvCheckResult *res;
    BdrvCheckMode fix;
    int ret;
} CheckCo;

static void bdrv_check_co_entry(void *opaque)
{
    CheckCo *cco = opaque;
    cco->ret = bdrv_co_check(cco->bs, cco->res, cco->fix);
}

int bdrv_check(BlockDriverState *bs,
               BdrvCheckResult *res, BdrvCheckMode fix)
{
    Coroutine *co;
    CheckCo cco = {
        .bs = bs,
        .res = res,
        .ret = -EINPROGRESS,
        .fix = fix,
    };

    if (qemu_in_coroutine()) {
        /* Fast-path if already in coroutine context */
        bdrv_check_co_entry(&cco);
    } else {
        co = qemu_coroutine_create(bdrv_check_co_entry, &cco);
        qemu_coroutine_enter(co);
        BDRV_POLL_WHILE(bs, cco.ret == -EINPROGRESS);
    }

    return cco.ret;
}

/*
@@ -3635,6 +3719,11 @@ int bdrv_truncate(BdrvChild *child, int64_t offset, PreallocMode prealloc,
        error_setg(errp, "No medium inserted");
        return -ENOMEDIUM;
    }
    if (offset < 0) {
        error_setg(errp, "Image size cannot be negative");
        return -EINVAL;
    }

    if (!drv->bdrv_truncate) {
        if (bs->file && drv->is_filter) {
            return bdrv_truncate(bs->file, offset, prealloc, errp);
@@ -4209,7 +4298,8 @@ void bdrv_init_with_whitelist(void)
    bdrv_init();
}

void bdrv_invalidate_cache(BlockDriverState *bs, Error **errp)
static void coroutine_fn bdrv_co_invalidate_cache(BlockDriverState *bs,
                                                  Error **errp)
{
    BdrvChild *child, *parent;
    uint64_t perm, shared_perm;
@@ -4225,7 +4315,7 @@ void bdrv_invalidate_cache(BlockDriverState *bs, Error **errp)
    }

    QLIST_FOREACH(child, &bs->children, next) {
        bdrv_invalidate_cache(child->bs, &local_err);
        bdrv_co_invalidate_cache(child->bs, &local_err);
        if (local_err) {
            error_propagate(errp, local_err);
            return;
@@ -4255,8 +4345,8 @@ void bdrv_invalidate_cache(BlockDriverState *bs, Error **errp)
    }
    bdrv_set_perm(bs, perm, shared_perm);

    if (bs->drv->bdrv_invalidate_cache) {
        bs->drv->bdrv_invalidate_cache(bs, &local_err);
    if (bs->drv->bdrv_co_invalidate_cache) {
        bs->drv->bdrv_co_invalidate_cache(bs, &local_err);
        if (local_err) {
            bs->open_flags |= BDRV_O_INACTIVE;
            error_propagate(errp, local_err);
@@ -4282,6 +4372,38 @@ void bdrv_invalidate_cache(BlockDriverState *bs, Error **errp)
    }
}

typedef struct InvalidateCacheCo {
    BlockDriverState *bs;
    Error **errp;
    bool done;
} InvalidateCacheCo;

static void coroutine_fn bdrv_invalidate_cache_co_entry(void *opaque)
{
    InvalidateCacheCo *ico = opaque;
    bdrv_co_invalidate_cache(ico->bs, ico->errp);
    ico->done = true;
}

void bdrv_invalidate_cache(BlockDriverState *bs, Error **errp)
{
    Coroutine *co;
    InvalidateCacheCo ico = {
        .bs = bs,
        .done = false,
        .errp = errp
    };

    if (qemu_in_coroutine()) {
        /* Fast-path if already in coroutine context */
        bdrv_invalidate_cache_co_entry(&ico);
    } else {
        co = qemu_coroutine_create(bdrv_invalidate_cache_co_entry, &ico);
        qemu_coroutine_enter(co);
        BDRV_POLL_WHILE(bs, !ico.done);
    }
}

void bdrv_invalidate_cache_all(Error **errp)
{
    BlockDriverState *bs;
+1 −1
Original line number Diff line number Diff line
@@ -9,7 +9,7 @@ block-obj-y += block-backend.o snapshot.o qapi.o
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-y += null.o mirror.o commit.o io.o
block-obj-y += null.o mirror.o commit.o io.o create.o
block-obj-y += throttle-groups.o
block-obj-$(CONFIG_LINUX) += nvme.o

block/create.c

0 → 100644
+76 −0
Original line number Diff line number Diff line
/*
 * Block layer code related to image creation
 *
 * Copyright (c) 2018 Kevin Wolf <kwolf@redhat.com>
 *
 * 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 "qapi/qapi-commands-block-core.h"
#include "qapi/error.h"

typedef struct BlockdevCreateCo {
    BlockDriver *drv;
    BlockdevCreateOptions *opts;
    int ret;
    Error **errp;
} BlockdevCreateCo;

static void coroutine_fn bdrv_co_create_co_entry(void *opaque)
{
    BlockdevCreateCo *cco = opaque;
    cco->ret = cco->drv->bdrv_co_create(cco->opts, cco->errp);
}

void qmp_x_blockdev_create(BlockdevCreateOptions *options, Error **errp)
{
    const char *fmt = BlockdevDriver_str(options->driver);
    BlockDriver *drv = bdrv_find_format(fmt);
    Coroutine *co;
    BlockdevCreateCo cco;

    /* If the driver is in the schema, we know that it exists. But it may not
     * be whitelisted. */
    assert(drv);
    if (bdrv_uses_whitelist() && !bdrv_is_whitelisted(drv, false)) {
        error_setg(errp, "Driver is not whitelisted");
        return;
    }

    /* Call callback if it exists */
    if (!drv->bdrv_co_create) {
        error_setg(errp, "Driver does not support blockdev-create");
        return;
    }

    cco = (BlockdevCreateCo) {
        .drv = drv,
        .opts = options,
        .ret = -EINPROGRESS,
        .errp = errp,
    };

    co = qemu_coroutine_create(bdrv_co_create_co_entry, &cco);
    qemu_coroutine_enter(co);
    while (cco.ret == -EINPROGRESS) {
        aio_poll(qemu_get_aio_context(), true);
    }
}
+7 −0
Original line number Diff line number Diff line
@@ -384,6 +384,12 @@ static void block_crypto_close(BlockDriverState *bs)
    qcrypto_block_free(crypto->block);
}

static int block_crypto_reopen_prepare(BDRVReopenState *state,
                                       BlockReopenQueue *queue, Error **errp)
{
    /* nothing needs checking */
    return 0;
}

/*
 * 1 MB bounce buffer gives good performance / memory tradeoff
@@ -621,6 +627,7 @@ BlockDriver bdrv_crypto_luks = {
    .bdrv_truncate      = block_crypto_truncate,
    .create_opts        = &block_crypto_create_opts_luks,

    .bdrv_reopen_prepare = block_crypto_reopen_prepare,
    .bdrv_refresh_limits = block_crypto_refresh_limits,
    .bdrv_co_preadv     = block_crypto_co_preadv,
    .bdrv_co_pwritev    = block_crypto_co_pwritev,
+65 −28
Original line number Diff line number Diff line
@@ -1686,12 +1686,16 @@ static int raw_regular_truncate(int fd, int64_t offset, PreallocMode prealloc,
         * file systems that do not support fallocate(), trying to check if a
         * block is allocated before allocating it, so don't do that here.
         */
        if (offset != current_length) {
            result = -posix_fallocate(fd, current_length, offset - current_length);
            if (result != 0) {
                /* posix_fallocate() doesn't set errno. */
                error_setg_errno(errp, -result,
                                 "Could not preallocate new data");
            }
        } else {
            result = 0;
        }
        goto out;
#endif
    case PREALLOC_MODE_FULL:
@@ -1982,34 +1986,25 @@ static int64_t raw_get_allocated_file_size(BlockDriverState *bs)
    return (int64_t)st.st_blocks * 512;
}

static int coroutine_fn raw_co_create_opts(const char *filename, QemuOpts *opts,
                                           Error **errp)
static int raw_co_create(BlockdevCreateOptions *options, Error **errp)
{
    BlockdevCreateOptionsFile *file_opts;
    int fd;
    int result = 0;
    int64_t total_size = 0;
    bool nocow = false;
    PreallocMode prealloc;
    char *buf = NULL;
    Error *local_err = NULL;

    strstart(filename, "file:", &filename);
    /* Validate options and set default values */
    assert(options->driver == BLOCKDEV_DRIVER_FILE);
    file_opts = &options->u.file;

    /* Read out options */
    total_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
                          BDRV_SECTOR_SIZE);
    nocow = qemu_opt_get_bool(opts, BLOCK_OPT_NOCOW, false);
    buf = qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC);
    prealloc = qapi_enum_parse(&PreallocMode_lookup, buf,
                               PREALLOC_MODE_OFF, &local_err);
    g_free(buf);
    if (local_err) {
        error_propagate(errp, local_err);
        result = -EINVAL;
        goto out;
    if (!file_opts->has_nocow) {
        file_opts->nocow = false;
    }
    if (!file_opts->has_preallocation) {
        file_opts->preallocation = PREALLOC_MODE_OFF;
    }

    fd = qemu_open(filename, O_RDWR | O_CREAT | O_TRUNC | O_BINARY,
    /* Create file */
    fd = qemu_open(file_opts->filename, O_RDWR | O_CREAT | O_TRUNC | O_BINARY,
                   0644);
    if (fd < 0) {
        result = -errno;
@@ -2017,7 +2012,7 @@ static int coroutine_fn raw_co_create_opts(const char *filename, QemuOpts *opts,
        goto out;
    }

    if (nocow) {
    if (file_opts->nocow) {
#ifdef __linux__
        /* Set NOCOW flag to solve performance issue on fs like btrfs.
         * This is an optimisation. The FS_IOC_SETFLAGS ioctl return value
@@ -2032,7 +2027,8 @@ static int coroutine_fn raw_co_create_opts(const char *filename, QemuOpts *opts,
#endif
    }

    result = raw_regular_truncate(fd, total_size, prealloc, errp);
    result = raw_regular_truncate(fd, file_opts->size, file_opts->preallocation,
                                  errp);
    if (result < 0) {
        goto out_close;
    }
@@ -2046,6 +2042,46 @@ out:
    return result;
}

static int coroutine_fn raw_co_create_opts(const char *filename, QemuOpts *opts,
                                           Error **errp)
{
    BlockdevCreateOptions options;
    int64_t total_size = 0;
    bool nocow = false;
    PreallocMode prealloc;
    char *buf = NULL;
    Error *local_err = NULL;

    /* Skip file: protocol prefix */
    strstart(filename, "file:", &filename);

    /* Read out options */
    total_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
                          BDRV_SECTOR_SIZE);
    nocow = qemu_opt_get_bool(opts, BLOCK_OPT_NOCOW, false);
    buf = qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC);
    prealloc = qapi_enum_parse(&PreallocMode_lookup, buf,
                               PREALLOC_MODE_OFF, &local_err);
    g_free(buf);
    if (local_err) {
        error_propagate(errp, local_err);
        return -EINVAL;
    }

    options = (BlockdevCreateOptions) {
        .driver     = BLOCKDEV_DRIVER_FILE,
        .u.file     = {
            .filename           = (char *) filename,
            .size               = total_size,
            .has_preallocation  = true,
            .preallocation      = prealloc,
            .has_nocow          = true,
            .nocow              = nocow,
        },
    };
    return raw_co_create(&options, errp);
}

/*
 * Find allocation range in @bs around offset @start.
 * May change underlying file descriptor's file offset.
@@ -2277,6 +2313,7 @@ BlockDriver bdrv_file = {
    .bdrv_reopen_commit = raw_reopen_commit,
    .bdrv_reopen_abort = raw_reopen_abort,
    .bdrv_close = raw_close,
    .bdrv_co_create = raw_co_create,
    .bdrv_co_create_opts = raw_co_create_opts,
    .bdrv_has_zero_init = bdrv_has_zero_init_1,
    .bdrv_co_block_status = raw_co_block_status,
Loading