Commit 6bd8ab68 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 Thu 19 May 2016 16:09:27 BST using RSA key ID C88F2FD6
# gpg: Good signature from "Kevin Wolf <kwolf@redhat.com>"

* remotes/kevin/tags/for-upstream: (31 commits)
  qemu-iotests: Fix regression in 136 on aio_read invalid
  qemu-iotests: Simplify 109 with unaligned qemu-img compare
  qemu-io: Fix recent UI updates
  block: clarify error message for qmp-eject
  qemu-iotests: Some more write_zeroes tests
  qcow2: Fix write_zeroes with partially allocated backing file cluster
  qcow2: fix condition in is_zero_cluster
  block: Propagate AioContext change to all children
  block: Remove BlockDriverState.blk
  block: Don't return throttling info in query-named-block-nodes
  block: Avoid bs->blk in bdrv_next()
  block: Add bdrv_has_blk()
  block: Remove bdrv_aio_multiwrite()
  blockjob: Don't touch BDS iostatus
  blockjob: Don't set iostatus of target
  block: User BdrvChild callback for device name
  block: Use BdrvChild callbacks for change_media/resize
  block: Don't check throttled reqs in bdrv_requests_pending()
  Revert "block: Forbid I/O throttling on nodes with multiple parents for 2.6"
  block: Remove bdrv_move_feature_fields()
  ...

Signed-off-by: default avatarPeter Maydell <peter.maydell@linaro.org>
parents 776efef3 7753da23
Loading
Loading
Loading
Loading
+64 −117
Original line number Diff line number Diff line
@@ -38,7 +38,6 @@
#include "qmp-commands.h"
#include "qemu/timer.h"
#include "qapi-event.h"
#include "block/throttle-groups.h"
#include "qemu/cutils.h"
#include "qemu/id.h"

@@ -237,8 +236,6 @@ BlockDriverState *bdrv_new(void)
        QLIST_INIT(&bs->op_blockers[i]);
    }
    notifier_with_return_list_init(&bs->before_write_notifiers);
    qemu_co_queue_init(&bs->throttled_reqs[0]);
    qemu_co_queue_init(&bs->throttled_reqs[1]);
    bs->refcnt = 1;
    bs->aio_context = qemu_get_aio_context();

@@ -1217,6 +1214,27 @@ void bdrv_unref_child(BlockDriverState *parent, BdrvChild *child)
    bdrv_root_unref_child(child);
}


static void bdrv_parent_cb_change_media(BlockDriverState *bs, bool load)
{
    BdrvChild *c;
    QLIST_FOREACH(c, &bs->parents, next_parent) {
        if (c->role->change_media) {
            c->role->change_media(c, load);
        }
    }
}

static void bdrv_parent_cb_resize(BlockDriverState *bs)
{
    BdrvChild *c;
    QLIST_FOREACH(c, &bs->parents, next_parent) {
        if (c->role->resize) {
            c->role->resize(c);
        }
    }
}

/*
 * Sets the backing file link of a BDS. A new reference is created; callers
 * which don't need their own reference any more must call bdrv_unref().
@@ -1525,12 +1543,6 @@ static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename,
            return -ENODEV;
        }

        if (bs->throttle_state) {
            error_setg(errp, "Cannot reference an existing block device for "
                       "which I/O throttling is enabled");
            return -EINVAL;
        }

        bdrv_ref(bs);
        *pbs = bs;
        return 0;
@@ -1682,9 +1694,7 @@ static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename,
    }

    if (!bdrv_key_required(bs)) {
        if (bs->blk) {
            blk_dev_change_media_cb(bs->blk, true);
        }
        bdrv_parent_cb_change_media(bs, true);
    } else if (!runstate_check(RUN_STATE_PRELAUNCH)
               && !runstate_check(RUN_STATE_INMIGRATE)
               && !runstate_check(RUN_STATE_PAUSED)) { /* HACK */
@@ -2123,11 +2133,6 @@ static void bdrv_close(BlockDriverState *bs)

    assert(!bs->job);

    /* Disable I/O limits and drain all pending throttled requests */
    if (bs->throttle_state) {
        bdrv_io_limits_disable(bs);
    }

    bdrv_drained_begin(bs); /* complete I/O */
    bdrv_flush(bs);
    bdrv_drain(bs); /* in case flush left pending I/O */
@@ -2135,9 +2140,7 @@ static void bdrv_close(BlockDriverState *bs)
    bdrv_release_named_dirty_bitmaps(bs);
    assert(QLIST_EMPTY(&bs->dirty_bitmaps));

    if (bs->blk) {
        blk_dev_change_media_cb(bs->blk, false);
    }
    bdrv_parent_cb_change_media(bs, false);

    if (bs->drv) {
        BdrvChild *child, *next;
@@ -2218,26 +2221,11 @@ void bdrv_close_all(void)
    }
}

/* Fields that need to stay with the top-level BDS */
static void bdrv_move_feature_fields(BlockDriverState *bs_dest,
                                     BlockDriverState *bs_src)
{
    /* move some fields that need to stay attached to the device */
}

static void change_parent_backing_link(BlockDriverState *from,
                                       BlockDriverState *to)
{
    BdrvChild *c, *next;

    if (from->blk) {
        /* FIXME We bypass blk_set_bs(), so we need to make these updates
         * manually. The root problem is not in this change function, but the
         * existence of BlockDriverState.blk. */
        to->blk = from->blk;
        from->blk = NULL;
    }

    QLIST_FOREACH_SAFE(c, &from->parents, next_parent, next) {
        assert(c->role != &child_backing);
        c->bs = to;
@@ -2248,22 +2236,6 @@ static void change_parent_backing_link(BlockDriverState *from,
    }
}

static void swap_feature_fields(BlockDriverState *bs_top,
                                BlockDriverState *bs_new)
{
    BlockDriverState tmp;

    bdrv_move_feature_fields(&tmp, bs_top);
    bdrv_move_feature_fields(bs_top, bs_new);
    bdrv_move_feature_fields(bs_new, &tmp);

    assert(!bs_new->throttle_state);
    if (bs_top->throttle_state) {
        bdrv_io_limits_enable(bs_new, throttle_group_get_name(bs_top));
        bdrv_io_limits_disable(bs_top);
    }
}

/*
 * Add new bs contents at the top of an image chain while the chain is
 * live, while keeping required fields on the top layer.
@@ -2286,11 +2258,8 @@ void bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top)
    assert(!bdrv_requests_pending(bs_new));

    bdrv_ref(bs_top);
    change_parent_backing_link(bs_top, bs_new);

    /* Some fields always stay on top of the backing file chain */
    swap_feature_fields(bs_top, bs_new);

    change_parent_backing_link(bs_top, bs_new);
    bdrv_set_backing_hd(bs_new, bs_top);
    bdrv_unref(bs_top);

@@ -2306,16 +2275,6 @@ void bdrv_replace_in_backing_chain(BlockDriverState *old, BlockDriverState *new)

    bdrv_ref(old);

    if (old->blk) {
        /* As long as these fields aren't in BlockBackend, but in the top-level
         * BlockDriverState, it's not possible for a BDS to have two BBs.
         *
         * We really want to copy the fields from old to new, but we go for a
         * swap instead so that pointers aren't duplicated and cause trouble.
         * (Also, bdrv_swap() used to do the same.) */
        assert(!new->blk);
        swap_feature_fields(old, new);
    }
    change_parent_backing_link(old, new);

    /* Change backing files if a previously independent node is added to the
@@ -2624,9 +2583,7 @@ int bdrv_truncate(BlockDriverState *bs, int64_t offset)
    if (ret == 0) {
        ret = refresh_total_sectors(bs, offset >> BDRV_SECTOR_BITS);
        bdrv_dirty_bitmap_truncate(bs);
        if (bs->blk) {
            blk_dev_resize_cb(bs->blk);
        }
        bdrv_parent_cb_resize(bs);
    }
    return ret;
}
@@ -2736,11 +2693,9 @@ int bdrv_set_key(BlockDriverState *bs, const char *key)
    if (ret < 0) {
        bs->valid_key = 0;
    } else if (!bs->valid_key) {
        bs->valid_key = 1;
        if (bs->blk) {
        /* call the change callback now, we skipped it on open */
            blk_dev_change_media_cb(bs->blk, true);
        }
        bs->valid_key = 1;
        bdrv_parent_cb_change_media(bs, true);
    }
    return ret;
}
@@ -2907,34 +2862,33 @@ BlockDriverState *bdrv_next_node(BlockDriverState *bs)
    return QTAILQ_NEXT(bs, node_list);
}

/* Iterates over all top-level BlockDriverStates, i.e. BDSs that are owned by
 * the monitor or attached to a BlockBackend */
BlockDriverState *bdrv_next(BlockDriverState *bs)
const char *bdrv_get_node_name(const BlockDriverState *bs)
{
    if (!bs || bs->blk) {
        bs = blk_next_root_bs(bs);
        if (bs) {
            return bs;
        }
    return bs->node_name;
}

    /* Ignore all BDSs that are attached to a BlockBackend here; they have been
     * handled by the above block already */
    do {
        bs = bdrv_next_monitor_owned(bs);
    } while (bs && bs->blk);
    return bs;
const char *bdrv_get_parent_name(const BlockDriverState *bs)
{
    BdrvChild *c;
    const char *name;

    /* If multiple parents have a name, just pick the first one. */
    QLIST_FOREACH(c, &bs->parents, next_parent) {
        if (c->role->get_name) {
            name = c->role->get_name(c);
            if (name && *name) {
                return name;
            }
        }
    }

const char *bdrv_get_node_name(const BlockDriverState *bs)
{
    return bs->node_name;
    return NULL;
}

/* TODO check what callers really want: bs->node_name or blk_name() */
const char *bdrv_get_device_name(const BlockDriverState *bs)
{
    return bs->blk ? blk_name(bs->blk) : "";
    return bdrv_get_parent_name(bs) ?: "";
}

/* This can be used to identify nodes that might not have a device
@@ -2943,7 +2897,7 @@ const char *bdrv_get_device_name(const BlockDriverState *bs)
 * absent, then this returns an empty (non-null) string. */
const char *bdrv_get_device_or_node_name(const BlockDriverState *bs)
{
    return bs->blk ? blk_name(bs->blk) : bs->node_name;
    return bdrv_get_parent_name(bs) ?: bs->node_name;
}

int bdrv_get_flags(BlockDriverState *bs)
@@ -3239,10 +3193,11 @@ void bdrv_invalidate_cache(BlockDriverState *bs, Error **errp)

void bdrv_invalidate_cache_all(Error **errp)
{
    BlockDriverState *bs = NULL;
    BlockDriverState *bs;
    Error *local_err = NULL;
    BdrvNextIterator *it = NULL;

    while ((bs = bdrv_next(bs)) != NULL) {
    while ((it = bdrv_next(it, &bs)) != NULL) {
        AioContext *aio_context = bdrv_get_aio_context(bs);

        aio_context_acquire(aio_context);
@@ -3284,10 +3239,11 @@ static int bdrv_inactivate_recurse(BlockDriverState *bs,
int bdrv_inactivate_all(void)
{
    BlockDriverState *bs = NULL;
    BdrvNextIterator *it = NULL;
    int ret = 0;
    int pass;

    while ((bs = bdrv_next(bs)) != NULL) {
    while ((it = bdrv_next(it, &bs)) != NULL) {
        aio_context_acquire(bdrv_get_aio_context(bs));
    }

@@ -3296,8 +3252,8 @@ int bdrv_inactivate_all(void)
     * the second pass sets the BDRV_O_INACTIVE flag so that no further write
     * is allowed. */
    for (pass = 0; pass < 2; pass++) {
        bs = NULL;
        while ((bs = bdrv_next(bs)) != NULL) {
        it = NULL;
        while ((it = bdrv_next(it, &bs)) != NULL) {
            ret = bdrv_inactivate_recurse(bs, pass);
            if (ret < 0) {
                goto out;
@@ -3306,8 +3262,8 @@ int bdrv_inactivate_all(void)
    }

out:
    bs = NULL;
    while ((bs = bdrv_next(bs)) != NULL) {
    it = NULL;
    while ((it = bdrv_next(it, &bs)) != NULL) {
        aio_context_release(bdrv_get_aio_context(bs));
    }

@@ -3653,6 +3609,7 @@ AioContext *bdrv_get_aio_context(BlockDriverState *bs)
void bdrv_detach_aio_context(BlockDriverState *bs)
{
    BdrvAioNotifier *baf;
    BdrvChild *child;

    if (!bs->drv) {
        return;
@@ -3662,17 +3619,11 @@ void bdrv_detach_aio_context(BlockDriverState *bs)
        baf->detach_aio_context(baf->opaque);
    }

    if (bs->throttle_state) {
        throttle_timers_detach_aio_context(&bs->throttle_timers);
    }
    if (bs->drv->bdrv_detach_aio_context) {
        bs->drv->bdrv_detach_aio_context(bs);
    }
    if (bs->file) {
        bdrv_detach_aio_context(bs->file->bs);
    }
    if (bs->backing) {
        bdrv_detach_aio_context(bs->backing->bs);
    QLIST_FOREACH(child, &bs->children, next) {
        bdrv_detach_aio_context(child->bs);
    }

    bs->aio_context = NULL;
@@ -3682,6 +3633,7 @@ void bdrv_attach_aio_context(BlockDriverState *bs,
                             AioContext *new_context)
{
    BdrvAioNotifier *ban;
    BdrvChild *child;

    if (!bs->drv) {
        return;
@@ -3689,18 +3641,12 @@ void bdrv_attach_aio_context(BlockDriverState *bs,

    bs->aio_context = new_context;

    if (bs->backing) {
        bdrv_attach_aio_context(bs->backing->bs, new_context);
    }
    if (bs->file) {
        bdrv_attach_aio_context(bs->file->bs, new_context);
    QLIST_FOREACH(child, &bs->children, next) {
        bdrv_attach_aio_context(child->bs, new_context);
    }
    if (bs->drv->bdrv_attach_aio_context) {
        bs->drv->bdrv_attach_aio_context(bs, new_context);
    }
    if (bs->throttle_state) {
        throttle_timers_attach_aio_context(&bs->throttle_timers, new_context);
    }

    QLIST_FOREACH(ban, &bs->aio_notifiers, list) {
        ban->attached_aio_context(new_context, ban->opaque);
@@ -3806,10 +3752,11 @@ bool bdrv_recurse_is_first_non_filter(BlockDriverState *bs,
 */
bool bdrv_is_first_non_filter(BlockDriverState *candidate)
{
    BlockDriverState *bs = NULL;
    BlockDriverState *bs;
    BdrvNextIterator *it = NULL;

    /* walk down the bs forest recursively */
    while ((bs = bdrv_next(bs)) != NULL) {
    while ((it = bdrv_next(it, &bs)) != NULL) {
        bool perm;

        /* try to recurse in this top level bs */
+4 −30
Original line number Diff line number Diff line
@@ -218,15 +218,6 @@ static void backup_set_speed(BlockJob *job, int64_t speed, Error **errp)
    ratelimit_set_speed(&s->limit, speed / BDRV_SECTOR_SIZE, SLICE_TIME);
}

static void backup_iostatus_reset(BlockJob *job)
{
    BackupBlockJob *s = container_of(job, BackupBlockJob, common);

    if (s->target->blk) {
        blk_iostatus_reset(s->target->blk);
    }
}

static void backup_cleanup_sync_bitmap(BackupBlockJob *job, int ret)
{
    BdrvDirtyBitmap *bm;
@@ -263,7 +254,6 @@ static const BlockJobDriver backup_job_driver = {
    .instance_size  = sizeof(BackupBlockJob),
    .job_type       = BLOCK_JOB_TYPE_BACKUP,
    .set_speed      = backup_set_speed,
    .iostatus_reset = backup_iostatus_reset,
    .commit         = backup_commit,
    .abort          = backup_abort,
};
@@ -272,11 +262,11 @@ static BlockErrorAction backup_error_action(BackupBlockJob *job,
                                            bool read, int error)
{
    if (read) {
        return block_job_error_action(&job->common, job->common.bs,
                                      job->on_source_error, true, error);
        return block_job_error_action(&job->common, job->on_source_error,
                                      true, error);
    } else {
        return block_job_error_action(&job->common, job->target,
                                      job->on_target_error, false, error);
        return block_job_error_action(&job->common, job->on_target_error,
                                      false, error);
    }
}

@@ -388,7 +378,6 @@ static void coroutine_fn backup_run(void *opaque)
    BackupCompleteData *data;
    BlockDriverState *bs = job->common.bs;
    BlockDriverState *target = job->target;
    BlockdevOnError on_target_error = job->on_target_error;
    NotifierWithReturn before_write = {
        .notify = backup_before_write_notify,
    };
@@ -404,11 +393,6 @@ static void coroutine_fn backup_run(void *opaque)

    job->done_bitmap = bitmap_new(end);

    if (target->blk) {
        blk_set_on_error(target->blk, on_target_error, on_target_error);
        blk_iostatus_enable(target->blk);
    }

    bdrv_add_before_write_notifier(bs, &before_write);

    if (job->sync_mode == MIRROR_SYNC_MODE_NONE) {
@@ -484,9 +468,6 @@ static void coroutine_fn backup_run(void *opaque)
    qemu_co_rwlock_unlock(&job->flush_rwlock);
    g_free(job->done_bitmap);

    if (target->blk) {
        blk_iostatus_disable(target->blk);
    }
    bdrv_op_unblock_all(target, job->common.blocker);

    data = g_malloc(sizeof(*data));
@@ -515,13 +496,6 @@ void backup_start(BlockDriverState *bs, BlockDriverState *target,
        return;
    }

    if ((on_source_error == BLOCKDEV_ON_ERROR_STOP ||
         on_source_error == BLOCKDEV_ON_ERROR_ENOSPC) &&
        (!bs->blk || !blk_iostatus_is_enabled(bs->blk))) {
        error_setg(errp, QERR_INVALID_PARAMETER, "on-source-error");
        return;
    }

    if (!bdrv_is_inserted(bs)) {
        error_setg(errp, "Device is not inserted: %s",
                   bdrv_get_device_name(bs));
+0 −19
Original line number Diff line number Diff line
@@ -293,22 +293,6 @@ static bool blkverify_recurse_is_first_non_filter(BlockDriverState *bs,
    return bdrv_recurse_is_first_non_filter(s->test_file->bs, candidate);
}

/* Propagate AioContext changes to ->test_file */
static void blkverify_detach_aio_context(BlockDriverState *bs)
{
    BDRVBlkverifyState *s = bs->opaque;

    bdrv_detach_aio_context(s->test_file->bs);
}

static void blkverify_attach_aio_context(BlockDriverState *bs,
                                         AioContext *new_context)
{
    BDRVBlkverifyState *s = bs->opaque;

    bdrv_attach_aio_context(s->test_file->bs, new_context);
}

static void blkverify_refresh_filename(BlockDriverState *bs, QDict *options)
{
    BDRVBlkverifyState *s = bs->opaque;
@@ -356,9 +340,6 @@ static BlockDriver bdrv_blkverify = {
    .bdrv_aio_writev                  = blkverify_aio_writev,
    .bdrv_aio_flush                   = blkverify_aio_flush,

    .bdrv_attach_aio_context          = blkverify_attach_aio_context,
    .bdrv_detach_aio_context          = blkverify_detach_aio_context,

    .is_filter                        = true,
    .bdrv_recurse_is_first_non_filter = blkverify_recurse_is_first_non_filter,
};
+190 −61
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@ struct BlockBackend {
    DriveInfo *legacy_dinfo;    /* null unless created by drive_new() */
    QTAILQ_ENTRY(BlockBackend) link;         /* for block_backends */
    QTAILQ_ENTRY(BlockBackend) monitor_link; /* for monitor_block_backends */
    BlockBackendPublic public;

    void *dev;                  /* attached device model, if any */
    /* TODO change to DeviceState when all users are qdevified */
@@ -74,6 +75,7 @@ static const AIOCBInfo block_backend_aiocb_info = {
};

static void drive_info_del(DriveInfo *dinfo);
static BlockBackend *bdrv_first_blk(BlockDriverState *bs);

/* All BlockBackends */
static QTAILQ_HEAD(, BlockBackend) block_backends =
@@ -90,9 +92,26 @@ static void blk_root_inherit_options(int *child_flags, QDict *child_options,
    /* We're not supposed to call this function for root nodes */
    abort();
}
static void blk_root_drained_begin(BdrvChild *child);
static void blk_root_drained_end(BdrvChild *child);

static void blk_root_change_media(BdrvChild *child, bool load);
static void blk_root_resize(BdrvChild *child);

static const char *blk_root_get_name(BdrvChild *child)
{
    return blk_name(child->opaque);
}

static const BdrvChildRole child_root = {
    .inherit_options    = blk_root_inherit_options,

    .change_media       = blk_root_change_media,
    .resize             = blk_root_resize,
    .get_name           = blk_root_get_name,

    .drained_begin      = blk_root_drained_begin,
    .drained_end        = blk_root_drained_end,
};

/*
@@ -106,8 +125,12 @@ BlockBackend *blk_new(Error **errp)

    blk = g_new0(BlockBackend, 1);
    blk->refcnt = 1;
    qemu_co_queue_init(&blk->public.throttled_reqs[0]);
    qemu_co_queue_init(&blk->public.throttled_reqs[1]);

    notifier_list_init(&blk->remove_bs_notifiers);
    notifier_list_init(&blk->insert_bs_notifiers);

    QTAILQ_INSERT_TAIL(&block_backends, blk, link);
    return blk;
}
@@ -128,7 +151,7 @@ BlockBackend *blk_new_with_bs(Error **errp)

    bs = bdrv_new_root();
    blk->root = bdrv_root_attach_child(bs, "root", &child_root);
    bs->blk = blk;
    blk->root->opaque = blk;
    return blk;
}

@@ -177,10 +200,6 @@ static void blk_delete(BlockBackend *blk)
    }
    assert(QLIST_EMPTY(&blk->remove_bs_notifiers.notifiers));
    assert(QLIST_EMPTY(&blk->insert_bs_notifiers.notifiers));
    if (blk->root_state.throttle_state) {
        g_free(blk->root_state.throttle_group);
        throttle_group_unref(blk->root_state.throttle_state);
    }
    QTAILQ_REMOVE(&block_backends, blk, link);
    drive_info_del(blk->legacy_dinfo);
    block_acct_cleanup(&blk->stats);
@@ -267,28 +286,50 @@ BlockBackend *blk_next(BlockBackend *blk)
               : QTAILQ_FIRST(&monitor_block_backends);
}

/*
 * Iterates over all BlockDriverStates which are attached to a BlockBackend.
 * This function is for use by bdrv_next().
 *
 * @bs must be NULL or a BDS that is attached to a BB.
 */
BlockDriverState *blk_next_root_bs(BlockDriverState *bs)
{
struct BdrvNextIterator {
    enum {
        BDRV_NEXT_BACKEND_ROOTS,
        BDRV_NEXT_MONITOR_OWNED,
    } phase;
    BlockBackend *blk;
    BlockDriverState *bs;
};

    if (bs) {
        assert(bs->blk);
        blk = bs->blk;
    } else {
        blk = NULL;
/* Iterates over all top-level BlockDriverStates, i.e. BDSs that are owned by
 * the monitor or attached to a BlockBackend */
BdrvNextIterator *bdrv_next(BdrvNextIterator *it, BlockDriverState **bs)
{
    if (!it) {
        it = g_new(BdrvNextIterator, 1);
        *it = (BdrvNextIterator) {
            .phase = BDRV_NEXT_BACKEND_ROOTS,
        };
    }

    /* 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) {
        do {
        blk = blk_all_next(blk);
    } while (blk && !blk->root);
            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));

    return blk ? blk->root->bs : NULL;
        if (*bs) {
            return it;
        }
        it->phase = BDRV_NEXT_MONITOR_OWNED;
    }

    /* Then return the monitor-owned BDSes without a BB attached. Ignore all
     * BDSes that are attached to a BlockBackend here; they have been handled
     * by the above block already */
    do {
        it->bs = bdrv_next_monitor_owned(it->bs);
        *bs = it->bs;
    } while (*bs && bdrv_has_blk(*bs));

    return *bs ? it : NULL;
}

/*
@@ -375,6 +416,26 @@ BlockDriverState *blk_bs(BlockBackend *blk)
    return blk->root ? blk->root->bs : NULL;
}

static BlockBackend *bdrv_first_blk(BlockDriverState *bs)
{
    BdrvChild *child;
    QLIST_FOREACH(child, &bs->parents, next_parent) {
        if (child->role == &child_root) {
            return child->opaque;
        }
    }

    return NULL;
}

/*
 * Returns true if @bs has an associated BlockBackend.
 */
bool bdrv_has_blk(BlockDriverState *bs)
{
    return bdrv_first_blk(bs) != NULL;
}

/*
 * Return @blk's DriveInfo if any, else null.
 */
@@ -410,18 +471,34 @@ BlockBackend *blk_by_legacy_dinfo(DriveInfo *dinfo)
    abort();
}

/*
 * Returns a pointer to the publicly accessible fields of @blk.
 */
BlockBackendPublic *blk_get_public(BlockBackend *blk)
{
    return &blk->public;
}

/*
 * Returns a BlockBackend given the associated @public fields.
 */
BlockBackend *blk_by_public(BlockBackendPublic *public)
{
    return container_of(public, BlockBackend, public);
}

/*
 * Disassociates the currently associated BlockDriverState from @blk.
 */
void blk_remove_bs(BlockBackend *blk)
{
    assert(blk->root->bs->blk == blk);

    notifier_list_notify(&blk->remove_bs_notifiers, blk);
    if (blk->public.throttle_state) {
        throttle_timers_detach_aio_context(&blk->public.throttle_timers);
    }

    blk_update_root_state(blk);

    blk->root->bs->blk = NULL;
    bdrv_root_unref_child(blk->root);
    blk->root = NULL;
}
@@ -431,12 +508,15 @@ void blk_remove_bs(BlockBackend *blk)
 */
void blk_insert_bs(BlockBackend *blk, BlockDriverState *bs)
{
    assert(!blk->root && !bs->blk);
    bdrv_ref(bs);
    blk->root = bdrv_root_attach_child(bs, "root", &child_root);
    bs->blk = blk;
    blk->root->opaque = blk;

    notifier_list_notify(&blk->insert_bs_notifiers, blk);
    if (blk->public.throttle_state) {
        throttle_timers_attach_aio_context(
            &blk->public.throttle_timers, bdrv_get_aio_context(bs));
    }
}

/*
@@ -525,6 +605,11 @@ void blk_dev_change_media_cb(BlockBackend *blk, bool load)
    }
}

static void blk_root_change_media(BdrvChild *child, bool load)
{
    blk_dev_change_media_cb(child->opaque, load);
}

/*
 * Does @blk's attached device model have removable media?
 * %true if no device model is attached.
@@ -579,8 +664,10 @@ bool blk_dev_is_medium_locked(BlockBackend *blk)
/*
 * Notify @blk's attached device model of a backend size change.
 */
void blk_dev_resize_cb(BlockBackend *blk)
static void blk_root_resize(BdrvChild *child)
{
    BlockBackend *blk = child->opaque;

    if (blk->dev_ops && blk->dev_ops->resize_cb) {
        blk->dev_ops->resize_cb(blk->dev_opaque);
    }
@@ -692,6 +779,11 @@ static int coroutine_fn blk_co_preadv(BlockBackend *blk, int64_t offset,
        return ret;
    }

    /* throttling disk I/O */
    if (blk->public.throttle_state) {
        throttle_group_co_io_limits_intercept(blk, bytes, false);
    }

    return bdrv_co_preadv(blk_bs(blk), offset, bytes, qiov, flags);
}

@@ -706,6 +798,11 @@ static int coroutine_fn blk_co_pwritev(BlockBackend *blk, int64_t offset,
        return ret;
    }

    /* throttling disk I/O */
    if (blk->public.throttle_state) {
        throttle_group_co_io_limits_intercept(blk, bytes, true);
    }

    if (!blk->enable_write_cache) {
        flags |= BDRV_REQ_FUA;
    }
@@ -775,7 +872,6 @@ static int blk_prw(BlockBackend *blk, int64_t offset, uint8_t *buf,
int blk_pread_unthrottled(BlockBackend *blk, int64_t offset, uint8_t *buf,
                          int count)
{
    BlockDriverState *bs = blk_bs(blk);
    int ret;

    ret = blk_check_byte_request(blk, offset, count);
@@ -783,9 +879,9 @@ int blk_pread_unthrottled(BlockBackend *blk, int64_t offset, uint8_t *buf,
        return ret;
    }

    bdrv_no_throttling_begin(bs);
    blk_root_drained_begin(blk->root);
    ret = blk_pread(blk, offset, buf, count);
    bdrv_no_throttling_end(bs);
    blk_root_drained_end(blk->root);
    return ret;
}

@@ -1008,20 +1104,6 @@ void blk_aio_cancel_async(BlockAIOCB *acb)
    bdrv_aio_cancel_async(acb);
}

int blk_aio_multiwrite(BlockBackend *blk, BlockRequest *reqs, int num_reqs)
{
    int i, ret;

    for (i = 0; i < num_reqs; i++) {
        ret = blk_check_request(blk, reqs[i].sector, reqs[i].nb_sectors);
        if (ret < 0) {
            return ret;
        }
    }

    return bdrv_aio_multiwrite(blk_bs(blk), reqs, num_reqs);
}

int blk_ioctl(BlockBackend *blk, unsigned long int req, void *buf)
{
    if (!blk_is_available(blk)) {
@@ -1334,7 +1416,14 @@ void blk_set_aio_context(BlockBackend *blk, AioContext *new_context)
    BlockDriverState *bs = blk_bs(blk);

    if (bs) {
        if (blk->public.throttle_state) {
            throttle_timers_detach_aio_context(&blk->public.throttle_timers);
        }
        bdrv_set_aio_context(bs, new_context);
        if (blk->public.throttle_state) {
            throttle_timers_attach_aio_context(&blk->public.throttle_timers,
                                               new_context);
        }
    }
}

@@ -1499,19 +1588,6 @@ void blk_update_root_state(BlockBackend *blk)
    blk->root_state.open_flags    = blk->root->bs->open_flags;
    blk->root_state.read_only     = blk->root->bs->read_only;
    blk->root_state.detect_zeroes = blk->root->bs->detect_zeroes;

    if (blk->root_state.throttle_group) {
        g_free(blk->root_state.throttle_group);
        throttle_group_unref(blk->root_state.throttle_state);
    }
    if (blk->root->bs->throttle_state) {
        const char *name = throttle_group_get_name(blk->root->bs);
        blk->root_state.throttle_group = g_strdup(name);
        blk->root_state.throttle_state = throttle_group_incref(name);
    } else {
        blk->root_state.throttle_group = NULL;
        blk->root_state.throttle_state = NULL;
    }
}

/*
@@ -1522,9 +1598,6 @@ void blk_update_root_state(BlockBackend *blk)
void blk_apply_root_state(BlockBackend *blk, BlockDriverState *bs)
{
    bs->detect_zeroes = blk->root_state.detect_zeroes;
    if (blk->root_state.throttle_group) {
        bdrv_io_limits_enable(bs, blk->root_state.throttle_group);
    }
}

/*
@@ -1587,3 +1660,59 @@ int blk_flush_all(void)

    return result;
}


/* throttling disk I/O limits */
void blk_set_io_limits(BlockBackend *blk, ThrottleConfig *cfg)
{
    throttle_group_config(blk, cfg);
}

void blk_io_limits_disable(BlockBackend *blk)
{
    assert(blk->public.throttle_state);
    bdrv_drained_begin(blk_bs(blk));
    throttle_group_unregister_blk(blk);
    bdrv_drained_end(blk_bs(blk));
}

/* should be called before blk_set_io_limits if a limit is set */
void blk_io_limits_enable(BlockBackend *blk, const char *group)
{
    assert(!blk->public.throttle_state);
    throttle_group_register_blk(blk, group);
}

void blk_io_limits_update_group(BlockBackend *blk, const char *group)
{
    /* this BB is not part of any group */
    if (!blk->public.throttle_state) {
        return;
    }

    /* this BB is a part of the same group than the one we want */
    if (!g_strcmp0(throttle_group_get_name(blk), group)) {
        return;
    }

    /* need to change the group this bs belong to */
    blk_io_limits_disable(blk);
    blk_io_limits_enable(blk, group);
}

static void blk_root_drained_begin(BdrvChild *child)
{
    BlockBackend *blk = child->opaque;

    if (blk->public.io_limits_disabled++ == 0) {
        throttle_group_restart_blk(blk);
    }
}

static void blk_root_drained_end(BdrvChild *child)
{
    BlockBackend *blk = child->opaque;

    assert(blk->public.io_limits_disabled);
    --blk->public.io_limits_disabled;
}
+0 −7
Original line number Diff line number Diff line
@@ -214,13 +214,6 @@ void commit_start(BlockDriverState *bs, BlockDriverState *base,
    BlockDriverState *overlay_bs;
    Error *local_err = NULL;

    if ((on_error == BLOCKDEV_ON_ERROR_STOP ||
         on_error == BLOCKDEV_ON_ERROR_ENOSPC) &&
        (!bs->blk || !blk_iostatus_is_enabled(bs->blk))) {
        error_setg(errp, "Invalid parameter combination");
        return;
    }

    assert(top != bs);
    if (top == base) {
        error_setg(errp, "Invalid files for merge: top and base are the same");
Loading