Commit d5a49c6e authored by Kevin Wolf's avatar Kevin Wolf
Browse files

Merge remote-tracking branch 'mreitz/tags/pull-block-2017-11-17' into queue-block



Block patches for 2.11.0-rc2

# gpg: Signature made Fri Nov 17 18:22:07 2017 CET
# gpg:                using RSA key F407DB0061D5CF40
# gpg: Good signature from "Max Reitz <mreitz@redhat.com>"
# Primary key fingerprint: 91BE B60A 30DB 3E88 57D1  1829 F407 DB00 61D5 CF40

* mreitz/tags/pull-block-2017-11-17:
  iotests: Make 087 pass without AIO enabled
  block: Make bdrv_next() keep strong references
  qcow2: Fix overly broad madvise()
  qcow2: Refuse to get unaligned offsets from cache
  qcow2: Add bounds check to get_refblock_offset()
  block: Guard against NULL bs->drv
  qcow2: Unaligned zero cluster in handle_alloc()
  qcow2: check_errors are fatal
  qcow2: reject unaligned offsets in write compressed
  iotests: Add test for failing qemu-img commit
  tests: Add check-qobject for equality tests
  iotests: Add test for non-string option reopening
  block: qobject_is_equal() in bdrv_reopen_prepare()
  qapi: Add qobject_is_equal()
  qapi/qlist: Add qlist_append_null() macro
  qapi/qnull: Add own header

Signed-off-by: default avatarKevin Wolf <kwolf@redhat.com>
parents 4096974e c0012e9a
Loading
Loading
Loading
Loading
+39 −12
Original line number Diff line number Diff line
@@ -720,6 +720,10 @@ static int refresh_total_sectors(BlockDriverState *bs, int64_t hint)
{
    BlockDriver *drv = bs->drv;

    if (!drv) {
        return -ENOMEDIUM;
    }

    /* Do not attempt drv->bdrv_getlength() on scsi-generic devices */
    if (bdrv_is_sg(bs))
        return 0;
@@ -3074,19 +3078,26 @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue,
        const QDictEntry *entry = qdict_first(reopen_state->options);

        do {
            QString *new_obj = qobject_to_qstring(entry->value);
            const char *new = qstring_get_str(new_obj);
            QObject *new = entry->value;
            QObject *old = qdict_get(reopen_state->bs->options, entry->key);

            /*
             * Caution: while qdict_get_try_str() is fine, getting
             * non-string types would require more care.  When
             * bs->options come from -blockdev or blockdev_add, its
             * members are typed according to the QAPI schema, but
             * when they come from -drive, they're all QString.
             * TODO: When using -drive to specify blockdev options, all values
             * will be strings; however, when using -blockdev, blockdev-add or
             * filenames using the json:{} pseudo-protocol, they will be
             * correctly typed.
             * In contrast, reopening options are (currently) always strings
             * (because you can only specify them through qemu-io; all other
             * callers do not specify any options).
             * Therefore, when using anything other than -drive to create a BDS,
             * this cannot detect non-string options as unchanged, because
             * qobject_is_equal() always returns false for objects of different
             * type.  In the future, this should be remedied by correctly typing
             * all options.  For now, this is not too big of an issue because
             * the user can simply omit options which cannot be changed anyway,
             * so they will stay unchanged.
             */
            const char *old = qdict_get_try_str(reopen_state->bs->options,
                                                entry->key);

            if (!old || strcmp(new, old)) {
            if (!qobject_is_equal(new, old)) {
                error_setg(errp, "Cannot change the option '%s'", entry->key);
                ret = -EINVAL;
                goto error;
@@ -3424,6 +3435,10 @@ int bdrv_change_backing_file(BlockDriverState *bs,
    BlockDriver *drv = bs->drv;
    int ret;

    if (!drv) {
        return -ENOMEDIUM;
    }

    /* Backing file format doesn't make sense without a backing file */
    if (backing_fmt && !backing_file) {
        return -EINVAL;
@@ -3909,7 +3924,9 @@ int bdrv_has_zero_init_1(BlockDriverState *bs)

int bdrv_has_zero_init(BlockDriverState *bs)
{
    assert(bs->drv);
    if (!bs->drv) {
        return 0;
    }

    /* If BS is a copy on write image, it is initialized to
       the contents of the base image, which may not be zeroes.  */
@@ -4238,6 +4255,7 @@ void bdrv_invalidate_cache_all(Error **errp)
        aio_context_release(aio_context);
        if (local_err) {
            error_propagate(errp, local_err);
            bdrv_next_cleanup(&it);
            return;
        }
    }
@@ -4249,6 +4267,10 @@ static int bdrv_inactivate_recurse(BlockDriverState *bs,
    BdrvChild *child, *parent;
    int ret;

    if (!bs->drv) {
        return -ENOMEDIUM;
    }

    if (!setting_flag && bs->drv->bdrv_inactivate) {
        ret = bs->drv->bdrv_inactivate(bs);
        if (ret < 0) {
@@ -4309,6 +4331,7 @@ int bdrv_inactivate_all(void)
        for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
            ret = bdrv_inactivate_recurse(bs, pass);
            if (ret < 0) {
                bdrv_next_cleanup(&it);
                goto out;
            }
        }
@@ -4783,6 +4806,9 @@ void bdrv_remove_aio_context_notifier(BlockDriverState *bs,
int bdrv_amend_options(BlockDriverState *bs, QemuOpts *opts,
                       BlockDriverAmendStatusCB *status_cb, void *cb_opaque)
{
    if (!bs->drv) {
        return -ENOMEDIUM;
    }
    if (!bs->drv->bdrv_amend_options) {
        return -ENOTSUP;
    }
@@ -4840,6 +4866,7 @@ bool bdrv_is_first_non_filter(BlockDriverState *candidate)

        /* candidate is the first non filter */
        if (perm) {
            bdrv_next_cleanup(&it);
            return true;
        }
    }
+46 −2
Original line number Diff line number Diff line
@@ -442,21 +442,37 @@ BlockBackend *blk_next(BlockBackend *blk)
 * the monitor or attached to a BlockBackend */
BlockDriverState *bdrv_next(BdrvNextIterator *it)
{
    BlockDriverState *bs;
    BlockDriverState *bs, *old_bs;

    /* Must be called from the main loop */
    assert(qemu_get_current_aio_context() == qemu_get_aio_context());

    /* First, return all root nodes of BlockBackends. In order to avoid
     * returning a BDS twice when multiple BBs refer to it, we only return it
     * if the BB is the first one in the parent list of the BDS. */
    if (it->phase == BDRV_NEXT_BACKEND_ROOTS) {
        BlockBackend *old_blk = it->blk;

        old_bs = old_blk ? blk_bs(old_blk) : NULL;

        do {
            it->blk = blk_all_next(it->blk);
            bs = it->blk ? blk_bs(it->blk) : NULL;
        } while (it->blk && (bs == NULL || bdrv_first_blk(bs) != it->blk));

        if (it->blk) {
            blk_ref(it->blk);
        }
        blk_unref(old_blk);

        if (bs) {
            bdrv_ref(bs);
            bdrv_unref(old_bs);
            return bs;
        }
        it->phase = BDRV_NEXT_MONITOR_OWNED;
    } else {
        old_bs = it->bs;
    }

    /* Then return the monitor-owned BDSes without a BB attached. Ignore all
@@ -467,18 +483,46 @@ BlockDriverState *bdrv_next(BdrvNextIterator *it)
        bs = it->bs;
    } while (bs && bdrv_has_blk(bs));

    if (bs) {
        bdrv_ref(bs);
    }
    bdrv_unref(old_bs);

    return bs;
}

BlockDriverState *bdrv_first(BdrvNextIterator *it)
static void bdrv_next_reset(BdrvNextIterator *it)
{
    *it = (BdrvNextIterator) {
        .phase = BDRV_NEXT_BACKEND_ROOTS,
    };
}

BlockDriverState *bdrv_first(BdrvNextIterator *it)
{
    bdrv_next_reset(it);
    return bdrv_next(it);
}

/* Must be called when aborting a bdrv_next() iteration before
 * bdrv_next() returns NULL */
void bdrv_next_cleanup(BdrvNextIterator *it)
{
    /* Must be called from the main loop */
    assert(qemu_get_current_aio_context() == qemu_get_aio_context());

    if (it->phase == BDRV_NEXT_BACKEND_ROOTS) {
        if (it->blk) {
            bdrv_unref(blk_bs(it->blk));
            blk_unref(it->blk);
        }
    } else {
        bdrv_unref(it->bs);
    }

    bdrv_next_reset(it);
}

/*
 * Add a BlockBackend into the list of backends referenced by the monitor, with
 * the given @name acting as the handle for the monitor.
+36 −0
Original line number Diff line number Diff line
@@ -853,6 +853,10 @@ static int coroutine_fn bdrv_driver_preadv(BlockDriverState *bs,

    assert(!(flags & ~BDRV_REQ_MASK));

    if (!drv) {
        return -ENOMEDIUM;
    }

    if (drv->bdrv_co_preadv) {
        return drv->bdrv_co_preadv(bs, offset, bytes, qiov, flags);
    }
@@ -894,6 +898,10 @@ static int coroutine_fn bdrv_driver_pwritev(BlockDriverState *bs,

    assert(!(flags & ~BDRV_REQ_MASK));

    if (!drv) {
        return -ENOMEDIUM;
    }

    if (drv->bdrv_co_pwritev) {
        ret = drv->bdrv_co_pwritev(bs, offset, bytes, qiov,
                                   flags & bs->supported_write_flags);
@@ -945,6 +953,10 @@ bdrv_driver_pwritev_compressed(BlockDriverState *bs, uint64_t offset,
{
    BlockDriver *drv = bs->drv;

    if (!drv) {
        return -ENOMEDIUM;
    }

    if (!drv->bdrv_co_pwritev_compressed) {
        return -ENOTSUP;
    }
@@ -975,6 +987,10 @@ static int coroutine_fn bdrv_co_do_copy_on_readv(BdrvChild *child,
                                    BDRV_REQUEST_MAX_BYTES);
    unsigned int progress = 0;

    if (!drv) {
        return -ENOMEDIUM;
    }

    /* FIXME We cannot require callers to have write permissions when all they
     * are doing is a read request. If we did things right, write permissions
     * would be obtained anyway, but internally by the copy-on-read code. As
@@ -1291,6 +1307,10 @@ static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs,
                        bs->bl.request_alignment);
    int max_transfer = MIN_NON_ZERO(bs->bl.max_transfer, MAX_BOUNCE_BUFFER);

    if (!drv) {
        return -ENOMEDIUM;
    }

    assert(alignment % bs->bl.request_alignment == 0);
    head = offset % alignment;
    tail = (offset + bytes) % alignment;
@@ -1397,6 +1417,10 @@ static int coroutine_fn bdrv_aligned_pwritev(BdrvChild *child,
    uint64_t bytes_remaining = bytes;
    int max_transfer;

    if (!drv) {
        return -ENOMEDIUM;
    }

    if (bdrv_has_readonly_bitmaps(bs)) {
        return -EPERM;
    }
@@ -1863,6 +1887,8 @@ static int coroutine_fn bdrv_co_block_status(BlockDriverState *bs,
        bytes = n;
    }

    /* Must be non-NULL or bdrv_getlength() would have failed */
    assert(bs->drv);
    if (!bs->drv->bdrv_co_get_block_status) {
        *pnum = bytes;
        ret = BDRV_BLOCK_DATA | BDRV_BLOCK_ALLOCATED;
@@ -2373,6 +2399,12 @@ int coroutine_fn bdrv_co_flush(BlockDriverState *bs)
    }

    BLKDBG_EVENT(bs->file, BLKDBG_FLUSH_TO_DISK);
    if (!bs->drv) {
        /* bs->drv->bdrv_co_flush() might have ejected the BDS
         * (even in case of apparent success) */
        ret = -ENOMEDIUM;
        goto out;
    }
    if (bs->drv->bdrv_co_flush_to_disk) {
        ret = bs->drv->bdrv_co_flush_to_disk(bs);
    } else if (bs->drv->bdrv_aio_flush) {
@@ -2542,6 +2574,10 @@ int coroutine_fn bdrv_co_pdiscard(BlockDriverState *bs, int64_t offset,
            num = max_pdiscard;
        }

        if (!bs->drv) {
            ret = -ENOMEDIUM;
            goto out;
        }
        if (bs->drv->bdrv_co_pdiscard) {
            ret = bs->drv->bdrv_co_pdiscard(bs, offset, num);
        } else {
+7 −1
Original line number Diff line number Diff line
@@ -39,8 +39,14 @@ BlockDeviceInfo *bdrv_block_device_info(BlockBackend *blk,
{
    ImageInfo **p_image_info;
    BlockDriverState *bs0;
    BlockDeviceInfo *info = g_malloc0(sizeof(*info));
    BlockDeviceInfo *info;

    if (!bs->drv) {
        error_setg(errp, "Block device %s is ejected", bs->node_name);
        return NULL;
    }

    info = g_malloc0(sizeof(*info));
    info->file                   = g_strdup(bs->filename);
    info->ro                     = bs->read_only;
    info->drv                    = g_strdup(bs->drv->format_name);
+22 −1
Original line number Diff line number Diff line
@@ -62,6 +62,18 @@ static inline int qcow2_cache_get_table_idx(BlockDriverState *bs,
    return idx;
}

static inline const char *qcow2_cache_get_name(BDRVQcow2State *s, Qcow2Cache *c)
{
    if (c == s->refcount_block_cache) {
        return "refcount block";
    } else if (c == s->l2_table_cache) {
        return "L2 table";
    } else {
        /* Do not abort, because this is not critical */
        return "unknown";
    }
}

static void qcow2_cache_table_release(BlockDriverState *bs, Qcow2Cache *c,
                                      int i, int num_tables)
{
@@ -73,7 +85,7 @@ static void qcow2_cache_table_release(BlockDriverState *bs, Qcow2Cache *c,
    size_t mem_size = (size_t) s->cluster_size * num_tables;
    size_t offset = QEMU_ALIGN_UP((uintptr_t) t, align) - (uintptr_t) t;
    size_t length = QEMU_ALIGN_DOWN(mem_size - offset, align);
    if (length > 0) {
    if (mem_size > offset && length > 0) {
        madvise((uint8_t *) t + offset, length, MADV_DONTNEED);
    }
#endif
@@ -314,9 +326,18 @@ static int qcow2_cache_do_get(BlockDriverState *bs, Qcow2Cache *c,
    uint64_t min_lru_counter = UINT64_MAX;
    int min_lru_index = -1;

    assert(offset != 0);

    trace_qcow2_cache_get(qemu_coroutine_self(), c == s->l2_table_cache,
                          offset, read_from_disk);

    if (offset_into_cluster(s, offset)) {
        qcow2_signal_corruption(bs, true, -1, -1, "Cannot get entry from %s "
                                "cache: Offset %#" PRIx64 " is unaligned",
                                qcow2_cache_get_name(s, c), offset);
        return -EIO;
    }

    /* Check if the table is already cached */
    i = lookup_index = (offset / s->cluster_size * 4) % c->size;
    do {
Loading