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

Merge remote-tracking branch 'mreitz/tags/pull-block-for-kevin-2016-05-12' into queue-block



Block patches for 2.7

# gpg: Signature made Thu May 12 15:34:13 2016 CEST using RSA key ID E838ACAD
# gpg: Good signature from "Max Reitz <mreitz@redhat.com>"

* mreitz/tags/pull-block-for-kevin-2016-05-12:
  qemu-iotests: iotests: fail hard if not run via "check"
  block: enable testing of LUKS driver with block I/O tests
  block: add support for encryption secrets in block I/O tests
  block: add support for --image-opts in block I/O tests
  qemu-io: Add 'write -z -u' to test MAY_UNMAP flag
  qemu-io: Add 'write -f' to test FUA flag
  qemu-io: Allow unaligned access by default
  qemu-io: Use bool for command line flags
  qemu-io: Make 'open' subcommand more like command line
  qemu-io: Add missing option documentation
  qmp: add monitor command to add/remove a child
  quorum: implement bdrv_add_child() and bdrv_del_child()
  Add new block driver interface to add/delete a BDS's child
  qemu-img: check block status of backing file when converting.
  iotests: fix the redirection order in 083

Signed-off-by: default avatarKevin Wolf <kwolf@redhat.com>
parents aad0b7a0 5a8fabf3
Loading
Loading
Loading
Loading
+53 −4
Original line number Diff line number Diff line
@@ -1174,7 +1174,7 @@ BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs,
    return child;
}

static BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs,
BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs,
                             BlockDriverState *child_bs,
                             const char *child_name,
                             const BdrvChildRole *child_role)
@@ -4011,3 +4011,52 @@ void bdrv_refresh_filename(BlockDriverState *bs)
        QDECREF(json);
    }
}

/*
 * Hot add/remove a BDS's child. So the user can take a child offline when
 * it is broken and take a new child online
 */
void bdrv_add_child(BlockDriverState *parent_bs, BlockDriverState *child_bs,
                    Error **errp)
{

    if (!parent_bs->drv || !parent_bs->drv->bdrv_add_child) {
        error_setg(errp, "The node %s does not support adding a child",
                   bdrv_get_device_or_node_name(parent_bs));
        return;
    }

    if (!QLIST_EMPTY(&child_bs->parents)) {
        error_setg(errp, "The node %s already has a parent",
                   child_bs->node_name);
        return;
    }

    parent_bs->drv->bdrv_add_child(parent_bs, child_bs, errp);
}

void bdrv_del_child(BlockDriverState *parent_bs, BdrvChild *child, Error **errp)
{
    BdrvChild *tmp;

    if (!parent_bs->drv || !parent_bs->drv->bdrv_del_child) {
        error_setg(errp, "The node %s does not support removing a child",
                   bdrv_get_device_or_node_name(parent_bs));
        return;
    }

    QLIST_FOREACH(tmp, &parent_bs->children, next) {
        if (tmp == child) {
            break;
        }
    }

    if (!tmp) {
        error_setg(errp, "The node %s does not have a child named %s",
                   bdrv_get_device_or_node_name(parent_bs),
                   bdrv_get_device_or_node_name(child->bs));
        return;
    }

    parent_bs->drv->bdrv_del_child(parent_bs, child, errp);
}
+76 −2
Original line number Diff line number Diff line
@@ -14,6 +14,7 @@
 */

#include "qemu/osdep.h"
#include "qemu/cutils.h"
#include "block/block_int.h"
#include "qapi/qmp/qbool.h"
#include "qapi/qmp/qdict.h"
@@ -67,6 +68,9 @@ typedef struct QuorumVotes {
typedef struct BDRVQuorumState {
    BdrvChild **children;  /* children BlockDriverStates */
    int num_children;      /* children count */
    unsigned next_child_index;  /* the index of the next child that should
                                 * be added
                                 */
    int threshold;         /* if less than threshold children reads gave the
                            * same result a quorum error occurs.
                            */
@@ -883,9 +887,9 @@ static int quorum_open(BlockDriverState *bs, QDict *options, int flags,
        ret = -EINVAL;
        goto exit;
    }
    if (s->num_children < 2) {
    if (s->num_children < 1) {
        error_setg(&local_err,
                   "Number of provided children must be greater than 1");
                   "Number of provided children must be 1 or more");
        ret = -EINVAL;
        goto exit;
    }
@@ -949,6 +953,7 @@ static int quorum_open(BlockDriverState *bs, QDict *options, int flags,

        opened[i] = true;
    }
    s->next_child_index = s->num_children;

    g_free(opened);
    goto exit;
@@ -1005,6 +1010,72 @@ static void quorum_attach_aio_context(BlockDriverState *bs,
    }
}

static void quorum_add_child(BlockDriverState *bs, BlockDriverState *child_bs,
                             Error **errp)
{
    BDRVQuorumState *s = bs->opaque;
    BdrvChild *child;
    char indexstr[32];
    int ret;

    assert(s->num_children <= INT_MAX / sizeof(BdrvChild *));
    if (s->num_children == INT_MAX / sizeof(BdrvChild *) ||
        s->next_child_index == UINT_MAX) {
        error_setg(errp, "Too many children");
        return;
    }

    ret = snprintf(indexstr, 32, "children.%u", s->next_child_index);
    if (ret < 0 || ret >= 32) {
        error_setg(errp, "cannot generate child name");
        return;
    }
    s->next_child_index++;

    bdrv_drained_begin(bs);

    /* We can safely add the child now */
    bdrv_ref(child_bs);
    child = bdrv_attach_child(bs, child_bs, indexstr, &child_format);
    s->children = g_renew(BdrvChild *, s->children, s->num_children + 1);
    s->children[s->num_children++] = child;

    bdrv_drained_end(bs);
}

static void quorum_del_child(BlockDriverState *bs, BdrvChild *child,
                             Error **errp)
{
    BDRVQuorumState *s = bs->opaque;
    int i;

    for (i = 0; i < s->num_children; i++) {
        if (s->children[i] == child) {
            break;
        }
    }

    /* we have checked it in bdrv_del_child() */
    assert(i < s->num_children);

    if (s->num_children <= s->threshold) {
        error_setg(errp,
            "The number of children cannot be lower than the vote threshold %d",
            s->threshold);
        return;
    }

    bdrv_drained_begin(bs);

    /* We can safely remove this child now */
    memmove(&s->children[i], &s->children[i + 1],
            (s->num_children - i - 1) * sizeof(BdrvChild *));
    s->children = g_renew(BdrvChild *, s->children, --s->num_children);
    bdrv_unref_child(bs, child);

    bdrv_drained_end(bs);
}

static void quorum_refresh_filename(BlockDriverState *bs, QDict *options)
{
    BDRVQuorumState *s = bs->opaque;
@@ -1059,6 +1130,9 @@ static BlockDriver bdrv_quorum = {
    .bdrv_detach_aio_context            = quorum_detach_aio_context,
    .bdrv_attach_aio_context            = quorum_attach_aio_context,

    .bdrv_add_child                     = quorum_add_child,
    .bdrv_del_child                     = quorum_del_child,

    .is_filter                          = true,
    .bdrv_recurse_is_first_non_filter   = quorum_recurse_is_first_non_filter,
};
+55 −0
Original line number Diff line number Diff line
@@ -4092,6 +4092,61 @@ out:
    aio_context_release(aio_context);
}

static BdrvChild *bdrv_find_child(BlockDriverState *parent_bs,
                                  const char *child_name)
{
    BdrvChild *child;

    QLIST_FOREACH(child, &parent_bs->children, next) {
        if (strcmp(child->name, child_name) == 0) {
            return child;
        }
    }

    return NULL;
}

void qmp_x_blockdev_change(const char *parent, bool has_child,
                           const char *child, bool has_node,
                           const char *node, Error **errp)
{
    BlockDriverState *parent_bs, *new_bs = NULL;
    BdrvChild *p_child;

    parent_bs = bdrv_lookup_bs(parent, parent, errp);
    if (!parent_bs) {
        return;
    }

    if (has_child == has_node) {
        if (has_child) {
            error_setg(errp, "The parameters child and node are in conflict");
        } else {
            error_setg(errp, "Either child or node must be specified");
        }
        return;
    }

    if (has_child) {
        p_child = bdrv_find_child(parent_bs, child);
        if (!p_child) {
            error_setg(errp, "Node '%s' does not have child '%s'",
                       parent, child);
            return;
        }
        bdrv_del_child(parent_bs, p_child, errp);
    }

    if (has_node) {
        new_bs = bdrv_find_node(node);
        if (!new_bs) {
            error_setg(errp, "Node '%s' not found", node);
            return;
        }
        bdrv_add_child(parent_bs, new_bs, errp);
    }
}

BlockJobInfoList *qmp_query_block_jobs(Error **errp)
{
    BlockJobInfoList *head = NULL, **p_next = &head;
+8 −0
Original line number Diff line number Diff line
@@ -476,6 +476,10 @@ void bdrv_disable_copy_on_read(BlockDriverState *bs);
void bdrv_ref(BlockDriverState *bs);
void bdrv_unref(BlockDriverState *bs);
void bdrv_unref_child(BlockDriverState *parent, BdrvChild *child);
BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs,
                             BlockDriverState *child_bs,
                             const char *child_name,
                             const BdrvChildRole *child_role);

bool bdrv_op_is_blocked(BlockDriverState *bs, BlockOpType op, Error **errp);
void bdrv_op_block(BlockDriverState *bs, BlockOpType op, Error *reason);
@@ -542,4 +546,8 @@ void bdrv_drained_begin(BlockDriverState *bs);
 */
void bdrv_drained_end(BlockDriverState *bs);

void bdrv_add_child(BlockDriverState *parent, BlockDriverState *child,
                    Error **errp);
void bdrv_del_child(BlockDriverState *parent, BdrvChild *child, Error **errp);

#endif
+5 −0
Original line number Diff line number Diff line
@@ -314,6 +314,11 @@ struct BlockDriver {
     */
    void (*bdrv_drain)(BlockDriverState *bs);

    void (*bdrv_add_child)(BlockDriverState *parent, BlockDriverState *child,
                           Error **errp);
    void (*bdrv_del_child)(BlockDriverState *parent, BdrvChild *child,
                           Error **errp);

    QLIST_ENTRY(BlockDriver) list;
};

Loading