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

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



Block layer patches:

- qcow2 cache option default changes (Linux: 32 MB maximum, limited by
  whatever cache size can be made use of with the specific image;
  default cache-clean-interval of 10 minutes)
- reopen: Allow specifying unchanged child node references, and changing
  a few generic options (discard, detect-zeroes)
- Fix werror/rerror defaults for -device drive=<node-name>
- Test case fixes

# gpg: Signature made Mon 01 Oct 2018 18:17:35 BST
# 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: (23 commits)
  tests/test-bdrv-drain: Fix too late qemu_event_reset()
  test-replication: Lock AioContext around blk_unref()
  qcow2: Fix cache-clean-interval documentation
  block-backend: Set werror/rerror defaults in blk_new()
  qcow2: Explicit number replaced by a constant
  qcow2: Set the default cache-clean-interval to 10 minutes
  qcow2: Resize the cache upon image resizing
  qcow2: Increase the default upper limit on the L2 cache size
  qcow2: Assign the L2 cache relatively to the image size
  qcow2: Avoid duplication in setting the refcount cache size
  qcow2: Make sizes more humanly readable
  include: Add a lookup table of sizes
  qcow2: Options' documentation fixes
  block: Allow changing 'detect-zeroes' on reopen
  block: Allow changing 'discard' on reopen
  file-posix: Forbid trying to change unsupported options during reopen
  block: Forbid trying to change unsupported options during reopen
  block: Allow child references on reopen
  block: Don't look for child references in append_open_options()
  block: Remove child references from bs->{options,explicit_options}
  ...

Signed-off-by: default avatarPeter Maydell <peter.maydell@linaro.org>
parents a2ef4d9e dd353157
Loading
Loading
Loading
Loading
+86 −49
Original line number Diff line number Diff line
@@ -764,6 +764,31 @@ static void bdrv_join_options(BlockDriverState *bs, QDict *options,
    }
}

static BlockdevDetectZeroesOptions bdrv_parse_detect_zeroes(QemuOpts *opts,
                                                            int open_flags,
                                                            Error **errp)
{
    Error *local_err = NULL;
    char *value = qemu_opt_get_del(opts, "detect-zeroes");
    BlockdevDetectZeroesOptions detect_zeroes =
        qapi_enum_parse(&BlockdevDetectZeroesOptions_lookup, value,
                        BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF, &local_err);
    g_free(value);
    if (local_err) {
        error_propagate(errp, local_err);
        return detect_zeroes;
    }

    if (detect_zeroes == BLOCKDEV_DETECT_ZEROES_OPTIONS_UNMAP &&
        !(open_flags & BDRV_O_UNMAP))
    {
        error_setg(errp, "setting detect-zeroes to unmap is not allowed "
                   "without setting discard operation to unmap");
    }

    return detect_zeroes;
}

/**
 * Set open flags for a given discard mode
 *
@@ -1094,19 +1119,19 @@ static void update_flags_from_options(int *flags, QemuOpts *opts)
    *flags &= ~BDRV_O_CACHE_MASK;

    assert(qemu_opt_find(opts, BDRV_OPT_CACHE_NO_FLUSH));
    if (qemu_opt_get_bool(opts, BDRV_OPT_CACHE_NO_FLUSH, false)) {
    if (qemu_opt_get_bool_del(opts, BDRV_OPT_CACHE_NO_FLUSH, false)) {
        *flags |= BDRV_O_NO_FLUSH;
    }

    assert(qemu_opt_find(opts, BDRV_OPT_CACHE_DIRECT));
    if (qemu_opt_get_bool(opts, BDRV_OPT_CACHE_DIRECT, false)) {
    if (qemu_opt_get_bool_del(opts, BDRV_OPT_CACHE_DIRECT, false)) {
        *flags |= BDRV_O_NOCACHE;
    }

    *flags &= ~BDRV_O_RDWR;

    assert(qemu_opt_find(opts, BDRV_OPT_READ_ONLY));
    if (!qemu_opt_get_bool(opts, BDRV_OPT_READ_ONLY, false)) {
    if (!qemu_opt_get_bool_del(opts, BDRV_OPT_READ_ONLY, false)) {
        *flags |= BDRV_O_RDWR;
    }

@@ -1328,7 +1353,6 @@ static int bdrv_open_common(BlockDriverState *bs, BlockBackend *file,
    const char *driver_name = NULL;
    const char *node_name = NULL;
    const char *discard;
    const char *detect_zeroes;
    QemuOpts *opts;
    BlockDriver *drv;
    Error *local_err = NULL;
@@ -1417,31 +1441,14 @@ static int bdrv_open_common(BlockDriverState *bs, BlockBackend *file,
        }
    }

    detect_zeroes = qemu_opt_get(opts, "detect-zeroes");
    if (detect_zeroes) {
        BlockdevDetectZeroesOptions value =
            qapi_enum_parse(&BlockdevDetectZeroesOptions_lookup,
                            detect_zeroes,
                            BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF,
                            &local_err);
    bs->detect_zeroes =
        bdrv_parse_detect_zeroes(opts, bs->open_flags, &local_err);
    if (local_err) {
        error_propagate(errp, local_err);
        ret = -EINVAL;
        goto fail_opts;
    }

        if (value == BLOCKDEV_DETECT_ZEROES_OPTIONS_UNMAP &&
            !(bs->open_flags & BDRV_O_UNMAP))
        {
            error_setg(errp, "setting detect-zeroes to unmap is not allowed "
                             "without setting discard operation to unmap");
            ret = -EINVAL;
            goto fail_opts;
        }

        bs->detect_zeroes = value;
    }

    if (filename != NULL) {
        pstrcpy(bs->filename, sizeof(bs->filename), filename);
    } else {
@@ -2763,12 +2770,15 @@ static BlockDriverState *bdrv_open_inherit(const char *filename,
        }
    }

    /* Remove all children options from bs->options and bs->explicit_options */
    /* Remove all children options and references
     * from bs->options and bs->explicit_options */
    QLIST_FOREACH(child, &bs->children, next) {
        char *child_key_dot;
        child_key_dot = g_strdup_printf("%s.", child->name);
        qdict_extract_subqdict(bs->explicit_options, NULL, child_key_dot);
        qdict_extract_subqdict(bs->options, NULL, child_key_dot);
        qdict_del(bs->explicit_options, child->name);
        qdict_del(bs->options, child->name);
        g_free(child_key_dot);
    }

@@ -3153,7 +3163,7 @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue,
    BlockDriver *drv;
    QemuOpts *opts;
    QDict *orig_reopen_opts;
    const char *value;
    char *discard = NULL;
    bool read_only;

    assert(reopen_state != NULL);
@@ -3176,18 +3186,28 @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue,

    update_flags_from_options(&reopen_state->flags, opts);

    /* node-name and driver must be unchanged. Put them back into the QDict, so
     * that they are checked at the end of this function. */
    value = qemu_opt_get(opts, "node-name");
    if (value) {
        qdict_put_str(reopen_state->options, "node-name", value);
    discard = qemu_opt_get_del(opts, "discard");
    if (discard != NULL) {
        if (bdrv_parse_discard_flags(discard, &reopen_state->flags) != 0) {
            error_setg(errp, "Invalid discard option");
            ret = -EINVAL;
            goto error;
        }
    }

    value = qemu_opt_get(opts, "driver");
    if (value) {
        qdict_put_str(reopen_state->options, "driver", value);
    reopen_state->detect_zeroes =
        bdrv_parse_detect_zeroes(opts, reopen_state->flags, &local_err);
    if (local_err) {
        error_propagate(errp, local_err);
        ret = -EINVAL;
        goto error;
    }

    /* All other options (including node-name and driver) must be unchanged.
     * Put them back into the QDict, so that they are checked at the end
     * of this function. */
    qemu_opts_to_qdict(opts, reopen_state->options);

    /* If we are to stay read-only, do not allow permission change
     * to r/w. Attempting to set to r/w may fail if either BDRV_O_ALLOW_RDWR is
     * not set, or if the BDS still has copy_on_read enabled */
@@ -3239,6 +3259,24 @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue,
            QObject *new = entry->value;
            QObject *old = qdict_get(reopen_state->bs->options, entry->key);

            /* Allow child references (child_name=node_name) as long as they
             * point to the current child (i.e. everything stays the same). */
            if (qobject_type(new) == QTYPE_QSTRING) {
                BdrvChild *child;
                QLIST_FOREACH(child, &reopen_state->bs->children, next) {
                    if (!strcmp(child->name, entry->key)) {
                        break;
                    }
                }

                if (child) {
                    const char *str = qobject_get_try_str(new);
                    if (!strcmp(child->bs->node_name, str)) {
                        continue; /* Found child with this name, skip option */
                    }
                }
            }

            /*
             * TODO: When using -drive to specify blockdev options, all values
             * will be strings; however, when using -blockdev, blockdev-add or
@@ -3278,6 +3316,7 @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue,
error:
    qemu_opts_del(opts);
    qobject_unref(orig_reopen_opts);
    g_free(discard);
    return ret;
}

@@ -3290,6 +3329,7 @@ void bdrv_reopen_commit(BDRVReopenState *reopen_state)
{
    BlockDriver *drv;
    BlockDriverState *bs;
    BdrvChild *child;
    bool old_can_write, new_can_write;

    assert(reopen_state != NULL);
@@ -3313,6 +3353,14 @@ void bdrv_reopen_commit(BDRVReopenState *reopen_state)
    bs->options            = reopen_state->options;
    bs->open_flags         = reopen_state->flags;
    bs->read_only = !(reopen_state->flags & BDRV_O_RDWR);
    bs->detect_zeroes      = reopen_state->detect_zeroes;

    /* Remove child references from bs->options and bs->explicit_options.
     * Child options were already removed in bdrv_reopen_queue_child() */
    QLIST_FOREACH(child, &bs->children, next) {
        qdict_del(bs->explicit_options, child->name);
        qdict_del(bs->options, child->name);
    }

    bdrv_refresh_limits(bs, NULL);

@@ -5139,23 +5187,12 @@ static bool append_open_options(QDict *d, BlockDriverState *bs)
{
    const QDictEntry *entry;
    QemuOptDesc *desc;
    BdrvChild *child;
    bool found_any = false;

    for (entry = qdict_first(bs->options); entry;
         entry = qdict_next(bs->options, entry))
    {
        /* Exclude node-name references to children */
        QLIST_FOREACH(child, &bs->children, next) {
            if (!strcmp(entry->key, child->name)) {
                break;
            }
        }
        if (child) {
            continue;
        }

        /* And exclude all non-driver-specific options */
        /* Exclude all non-driver-specific options */
        for (desc = bdrv_runtime_opts.desc; desc->name; desc++) {
            if (!strcmp(qdict_entry_key(entry), desc->name)) {
                break;
+3 −0
Original line number Diff line number Diff line
@@ -325,6 +325,9 @@ BlockBackend *blk_new(uint64_t perm, uint64_t shared_perm)
    blk->shared_perm = shared_perm;
    blk_set_enable_write_cache(blk, true);

    blk->on_read_error = BLOCKDEV_ON_ERROR_REPORT;
    blk->on_write_error = BLOCKDEV_ON_ERROR_ENOSPC;

    block_acct_init(&blk->stats);

    notifier_list_init(&blk->remove_bs_notifiers);
+13 −6
Original line number Diff line number Diff line
@@ -741,8 +741,6 @@ static int raw_check_lock_bytes(int fd, uint64_t perm, uint64_t shared_perm,
                           "Failed to get \"%s\" lock",
                           perm_name);
                g_free(perm_name);
                error_append_hint(errp,
                                  "Is another process using the image?\n");
                return ret;
            }
        }
@@ -758,8 +756,6 @@ static int raw_check_lock_bytes(int fd, uint64_t perm, uint64_t shared_perm,
                           "Failed to get shared \"%s\" lock",
                           perm_name);
                g_free(perm_name);
                error_append_hint(errp,
                                  "Is another process using the image?\n");
                return ret;
            }
        }
@@ -796,6 +792,9 @@ static int raw_handle_perm_lock(BlockDriverState *bs,
            if (!ret) {
                return 0;
            }
            error_append_hint(errp,
                              "Is another process using the image [%s]?\n",
                              bs->filename);
        }
        op = RAW_PL_ABORT;
        /* fall through to unlock bytes. */
@@ -850,8 +849,13 @@ static int raw_reopen_prepare(BDRVReopenState *state,
        goto out;
    }

    rs->check_cache_dropped = qemu_opt_get_bool(opts, "x-check-cache-dropped",
                                                s->check_cache_dropped);
    rs->check_cache_dropped =
        qemu_opt_get_bool_del(opts, "x-check-cache-dropped", false);

    /* This driver's reopen function doesn't currently allow changing
     * other options, so let's put them back in the original QDict and
     * bdrv_reopen_prepare() will detect changes and complain. */
    qemu_opts_to_qdict(opts, state->options);

    if (s->type == FTYPE_CD) {
        rs->open_flags |= O_NONBLOCK;
@@ -2217,6 +2221,9 @@ raw_co_create(BlockdevCreateOptions *options, Error **errp)
    /* Step two: Check that nobody else has taken conflicting locks */
    result = raw_check_lock_bytes(fd, perm, shared, errp);
    if (result < 0) {
        error_append_hint(errp,
                          "Is another process using the image [%s]?\n",
                          file_opts->filename);
        goto out_unlock;
    }

+25 −18
Original line number Diff line number Diff line
@@ -777,29 +777,35 @@ static void read_cache_sizes(BlockDriverState *bs, QemuOpts *opts,
                             uint64_t *refcount_cache_size, Error **errp)
{
    BDRVQcow2State *s = bs->opaque;
    uint64_t combined_cache_size;
    uint64_t combined_cache_size, l2_cache_max_setting;
    bool l2_cache_size_set, refcount_cache_size_set, combined_cache_size_set;
    int min_refcount_cache = MIN_REFCOUNT_CACHE_SIZE * s->cluster_size;
    uint64_t virtual_disk_size = bs->total_sectors * BDRV_SECTOR_SIZE;
    uint64_t max_l2_cache = virtual_disk_size / (s->cluster_size / 8);

    combined_cache_size_set = qemu_opt_get(opts, QCOW2_OPT_CACHE_SIZE);
    l2_cache_size_set = qemu_opt_get(opts, QCOW2_OPT_L2_CACHE_SIZE);
    refcount_cache_size_set = qemu_opt_get(opts, QCOW2_OPT_REFCOUNT_CACHE_SIZE);

    combined_cache_size = qemu_opt_get_size(opts, QCOW2_OPT_CACHE_SIZE, 0);
    *l2_cache_size = qemu_opt_get_size(opts, QCOW2_OPT_L2_CACHE_SIZE, 0);
    l2_cache_max_setting = qemu_opt_get_size(opts, QCOW2_OPT_L2_CACHE_SIZE,
                                             DEFAULT_L2_CACHE_MAX_SIZE);
    *refcount_cache_size = qemu_opt_get_size(opts,
                                             QCOW2_OPT_REFCOUNT_CACHE_SIZE, 0);

    *l2_cache_entry_size = qemu_opt_get_size(
        opts, QCOW2_OPT_L2_CACHE_ENTRY_SIZE, s->cluster_size);

    *l2_cache_size = MIN(max_l2_cache, l2_cache_max_setting);

    if (combined_cache_size_set) {
        if (l2_cache_size_set && refcount_cache_size_set) {
            error_setg(errp, QCOW2_OPT_CACHE_SIZE ", " QCOW2_OPT_L2_CACHE_SIZE
                       " and " QCOW2_OPT_REFCOUNT_CACHE_SIZE " may not be set "
                       "at the same time");
            return;
        } else if (*l2_cache_size > combined_cache_size) {
        } else if (l2_cache_size_set &&
                   (l2_cache_max_setting > combined_cache_size)) {
            error_setg(errp, QCOW2_OPT_L2_CACHE_SIZE " may not exceed "
                       QCOW2_OPT_CACHE_SIZE);
            return;
@@ -814,9 +820,6 @@ static void read_cache_sizes(BlockDriverState *bs, QemuOpts *opts,
        } else if (refcount_cache_size_set) {
            *l2_cache_size = combined_cache_size - *refcount_cache_size;
        } else {
            uint64_t virtual_disk_size = bs->total_sectors * BDRV_SECTOR_SIZE;
            uint64_t max_l2_cache = virtual_disk_size / (s->cluster_size / 8);

            /* Assign as much memory as possible to the L2 cache, and
             * use the remainder for the refcount cache */
            if (combined_cache_size >= max_l2_cache + min_refcount_cache) {
@@ -828,16 +831,9 @@ static void read_cache_sizes(BlockDriverState *bs, QemuOpts *opts,
                *l2_cache_size = combined_cache_size - *refcount_cache_size;
            }
        }
    } else {
        if (!l2_cache_size_set) {
            *l2_cache_size = MAX(DEFAULT_L2_CACHE_BYTE_SIZE,
                                 (uint64_t)DEFAULT_L2_CACHE_CLUSTERS
                                 * s->cluster_size);
        }
        if (!refcount_cache_size_set) {
            *refcount_cache_size = min_refcount_cache;
        }
    }
    /* l2_cache_size and refcount_cache_size are ensured to have at least
     * their minimum values in qcow2_update_options_prepare() */

    if (*l2_cache_entry_size < (1 << MIN_CLUSTER_BITS) ||
        *l2_cache_entry_size > s->cluster_size ||
@@ -948,7 +944,7 @@ static int qcow2_update_options_prepare(BlockDriverState *bs,
    /* New interval for cache cleanup timer */
    r->cache_clean_interval =
        qemu_opt_get_number(opts, QCOW2_OPT_CACHE_CLEAN_INTERVAL,
                            s->cache_clean_interval);
                            DEFAULT_CACHE_CLEAN_INTERVAL);
#ifndef CONFIG_LINUX
    if (r->cache_clean_interval != 0) {
        error_setg(errp, QCOW2_OPT_CACHE_CLEAN_INTERVAL
@@ -1328,7 +1324,7 @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
    /* 2^(s->refcount_order - 3) is the refcount width in bytes */
    s->refcount_block_bits = s->cluster_bits - (s->refcount_order - 3);
    s->refcount_block_size = 1 << s->refcount_block_bits;
    bs->total_sectors = header.size / 512;
    bs->total_sectors = header.size / BDRV_SECTOR_SIZE;
    s->csize_shift = (62 - (s->cluster_bits - 8));
    s->csize_mask = (1 << (s->cluster_bits - 8)) - 1;
    s->cluster_offset_mask = (1LL << s->csize_shift) - 1;
@@ -3422,6 +3418,7 @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset,
    uint64_t old_length;
    int64_t new_l1_size;
    int ret;
    QDict *options;

    if (prealloc != PREALLOC_MODE_OFF && prealloc != PREALLOC_MODE_METADATA &&
        prealloc != PREALLOC_MODE_FALLOC && prealloc != PREALLOC_MODE_FULL)
@@ -3453,7 +3450,7 @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset,
        goto fail;
    }

    old_length = bs->total_sectors * 512;
    old_length = bs->total_sectors * BDRV_SECTOR_SIZE;
    new_l1_size = size_to_l1(s, offset);

    if (offset < old_length) {
@@ -3646,6 +3643,8 @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset,
        }
    }

    bs->total_sectors = offset / BDRV_SECTOR_SIZE;

    /* write updated header.size */
    offset = cpu_to_be64(offset);
    ret = bdrv_pwrite_sync(bs->file, offsetof(QCowHeader, size),
@@ -3656,6 +3655,14 @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset,
    }

    s->l1_vm_state_index = new_l1_size;

    /* Update cache sizes */
    options = qdict_clone_shallow(bs->options);
    ret = qcow2_update_options(bs, options, s->flags, errp);
    qobject_unref(options);
    if (ret < 0) {
        goto fail;
    }
    ret = 0;
fail:
    qemu_co_mutex_unlock(&s->lock);
+12 −7
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@

#include "crypto/block.h"
#include "qemu/coroutine.h"
#include "qemu/units.h"

//#define DEBUG_ALLOC
//#define DEBUG_ALLOC2
@@ -43,11 +44,11 @@

/* 8 MB refcount table is enough for 2 PB images at 64k cluster size
 * (128 GB for 512 byte clusters, 2 EB for 2 MB clusters) */
#define QCOW_MAX_REFTABLE_SIZE 0x800000
#define QCOW_MAX_REFTABLE_SIZE S_8MiB

/* 32 MB L1 table is enough for 2 PB images at 64k cluster size
 * (128 GB for 512 byte clusters, 2 EB for 2 MB clusters) */
#define QCOW_MAX_L1_SIZE 0x2000000
#define QCOW_MAX_L1_SIZE S_32MiB

/* Allow for an average of 1k per snapshot table entry, should be plenty of
 * space for snapshot names and IDs */
@@ -73,12 +74,16 @@
/* Must be at least 4 to cover all cases of refcount table growth */
#define MIN_REFCOUNT_CACHE_SIZE 4 /* clusters */

/* Whichever is more */
#define DEFAULT_L2_CACHE_CLUSTERS 8 /* clusters */
#define DEFAULT_L2_CACHE_BYTE_SIZE 1048576 /* bytes */

#define DEFAULT_CLUSTER_SIZE 65536
#ifdef CONFIG_LINUX
#define DEFAULT_L2_CACHE_MAX_SIZE S_32MiB
#define DEFAULT_CACHE_CLEAN_INTERVAL 600  /* seconds */
#else
#define DEFAULT_L2_CACHE_MAX_SIZE S_8MiB
/* Cache clean interval is currently available only on Linux, so must be 0 */
#define DEFAULT_CACHE_CLEAN_INTERVAL 0
#endif

#define DEFAULT_CLUSTER_SIZE S_64KiB

#define QCOW2_OPT_LAZY_REFCOUNTS "lazy-refcounts"
#define QCOW2_OPT_DISCARD_REQUEST "pass-discard-request"
Loading