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

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



Block layer fixes for 2.9.0-rc0

# gpg: Signature made Tue 07 Mar 2017 14:59:18 GMT
# gpg:                using RSA key 0x7F09B272C88F2FD6
# 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: (27 commits)
  commit: Don't use error_abort in commit_start
  block: Don't use error_abort in blk_new_open
  sheepdog: Support blockdev-add
  qapi-schema: Rename SocketAddressFlat's variant tcp to inet
  qapi-schema: Rename GlusterServer to SocketAddressFlat
  gluster: Plug memory leaks in qemu_gluster_parse_json()
  gluster: Don't duplicate qapi-util.c's qapi_enum_parse()
  gluster: Drop assumptions on SocketTransport names
  sheepdog: Implement bdrv_parse_filename()
  sheepdog: Use SocketAddress and socket_connect()
  sheepdog: Report errors in pseudo-filename more usefully
  sheepdog: Don't truncate long VDI name in _open(), _create()
  sheepdog: Fix snapshot ID parsing in _open(), _create, _goto()
  sheepdog: Mark sd_snapshot_delete() lossage FIXME
  sheepdog: Fix error handling sd_create()
  sheepdog: Fix error handling in sd_snapshot_delete()
  sheepdog: Defuse time bomb in sd_open() error handling
  block: Fix error handling in bdrv_replace_in_backing_chain()
  block: Handle permission errors in change_parent_backing_link()
  block: Ignore multiple children in bdrv_check_update_perm()
  ...

Signed-off-by: default avatarPeter Maydell <peter.maydell@linaro.org>
parents 87467097 b69f00dd
Loading
Loading
Loading
Loading
+120 −62
Original line number Diff line number Diff line
@@ -1403,7 +1403,8 @@ static int bdrv_fill_options(QDict **options, const char *filename,
 * or bdrv_abort_perm_update().
 */
static int bdrv_check_perm(BlockDriverState *bs, uint64_t cumulative_perms,
                           uint64_t cumulative_shared_perms, Error **errp)
                           uint64_t cumulative_shared_perms,
                           GSList *ignore_children, Error **errp)
{
    BlockDriver *drv = bs->drv;
    BdrvChild *c;
@@ -1439,7 +1440,8 @@ static int bdrv_check_perm(BlockDriverState *bs, uint64_t cumulative_perms,
        drv->bdrv_child_perm(bs, c, c->role,
                             cumulative_perms, cumulative_shared_perms,
                             &cur_perm, &cur_shared);
        ret = bdrv_child_check_perm(c, cur_perm, cur_shared, errp);
        ret = bdrv_child_check_perm(c, cur_perm, cur_shared, ignore_children,
                                    errp);
        if (ret < 0) {
            return ret;
        }
@@ -1559,15 +1561,15 @@ static char *bdrv_perm_names(uint64_t perm)

/*
 * Checks whether a new reference to @bs can be added if the new user requires
 * @new_used_perm/@new_shared_perm as its permissions. If @ignore_child is set,
 * this old reference is ignored in the calculations; this allows checking
 * permission updates for an existing reference.
 * @new_used_perm/@new_shared_perm as its permissions. If @ignore_children is
 * set, the BdrvChild objects in this list are ignored in the calculations;
 * this allows checking permission updates for an existing reference.
 *
 * Needs to be followed by a call to either bdrv_set_perm() or
 * bdrv_abort_perm_update(). */
static int bdrv_check_update_perm(BlockDriverState *bs, uint64_t new_used_perm,
                                  uint64_t new_shared_perm,
                                  BdrvChild *ignore_child, Error **errp)
                                  GSList *ignore_children, Error **errp)
{
    BdrvChild *c;
    uint64_t cumulative_perms = new_used_perm;
@@ -1577,7 +1579,7 @@ static int bdrv_check_update_perm(BlockDriverState *bs, uint64_t new_used_perm,
    assert(new_shared_perm & BLK_PERM_WRITE_UNCHANGED);

    QLIST_FOREACH(c, &bs->parents, next_parent) {
        if (c == ignore_child) {
        if (g_slist_find(ignore_children, c)) {
            continue;
        }

@@ -1607,15 +1609,22 @@ static int bdrv_check_update_perm(BlockDriverState *bs, uint64_t new_used_perm,
        cumulative_shared_perms &= c->shared_perm;
    }

    return bdrv_check_perm(bs, cumulative_perms, cumulative_shared_perms, errp);
    return bdrv_check_perm(bs, cumulative_perms, cumulative_shared_perms,
                           ignore_children, errp);
}

/* Needs to be followed by a call to either bdrv_child_set_perm() or
 * bdrv_child_abort_perm_update(). */
int bdrv_child_check_perm(BdrvChild *c, uint64_t perm, uint64_t shared,
                          Error **errp)
                          GSList *ignore_children, Error **errp)
{
    return bdrv_check_update_perm(c->bs, perm, shared, c, errp);
    int ret;

    ignore_children = g_slist_prepend(g_slist_copy(ignore_children), c);
    ret = bdrv_check_update_perm(c->bs, perm, shared, ignore_children, errp);
    g_slist_free(ignore_children);

    return ret;
}

void bdrv_child_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared)
@@ -1640,7 +1649,7 @@ int bdrv_child_try_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared,
{
    int ret;

    ret = bdrv_child_check_perm(c, perm, shared, errp);
    ret = bdrv_child_check_perm(c, perm, shared, NULL, errp);
    if (ret < 0) {
        bdrv_child_abort_perm_update(c);
        return ret;
@@ -1718,11 +1727,10 @@ void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c,
    *nshared = shared;
}

static void bdrv_replace_child(BdrvChild *child, BlockDriverState *new_bs,
                               bool check_new_perm)
static void bdrv_replace_child_noperm(BdrvChild *child,
                                      BlockDriverState *new_bs)
{
    BlockDriverState *old_bs = child->bs;
    uint64_t perm, shared_perm;

    if (old_bs) {
        if (old_bs->quiesce_counter && child->role->drained_end) {
@@ -1732,13 +1740,6 @@ static void bdrv_replace_child(BdrvChild *child, BlockDriverState *new_bs,
            child->role->detach(child);
        }
        QLIST_REMOVE(child, next_parent);

        /* Update permissions for old node. This is guaranteed to succeed
         * because we're just taking a parent away, so we're loosening
         * restrictions. */
        bdrv_get_cumulative_perm(old_bs, &perm, &shared_perm);
        bdrv_check_perm(old_bs, perm, shared_perm, &error_abort);
        bdrv_set_perm(old_bs, perm, shared_perm);
    }

    child->bs = new_bs;
@@ -1749,15 +1750,35 @@ static void bdrv_replace_child(BdrvChild *child, BlockDriverState *new_bs,
            child->role->drained_begin(child);
        }

        if (child->role->attach) {
            child->role->attach(child);
        }
    }
}

static void bdrv_replace_child(BdrvChild *child, BlockDriverState *new_bs,
                               bool check_new_perm)
{
    BlockDriverState *old_bs = child->bs;
    uint64_t perm, shared_perm;

    if (old_bs) {
        /* Update permissions for old node. This is guaranteed to succeed
         * because we're just taking a parent away, so we're loosening
         * restrictions. */
        bdrv_get_cumulative_perm(old_bs, &perm, &shared_perm);
        bdrv_check_perm(old_bs, perm, shared_perm, NULL, &error_abort);
        bdrv_set_perm(old_bs, perm, shared_perm);
    }

    bdrv_replace_child_noperm(child, new_bs);

    if (new_bs) {
        bdrv_get_cumulative_perm(new_bs, &perm, &shared_perm);
        if (check_new_perm) {
            bdrv_check_perm(new_bs, perm, shared_perm, &error_abort);
            bdrv_check_perm(new_bs, perm, shared_perm, NULL, &error_abort);
        }
        bdrv_set_perm(new_bs, perm, shared_perm);

        if (child->role->attach) {
            child->role->attach(child);
        }
    }
}

@@ -2891,15 +2912,14 @@ void bdrv_close_all(void)
    assert(QTAILQ_EMPTY(&all_bdrv_states));
}

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

    QLIST_FOREACH_SAFE(c, &from->parents, next_parent, next) {
    if (c->role->stay_at_node) {
            continue;
        return false;
    }

    if (c->role == &child_backing) {
        /* If @from is a backing file of @to, ignore the child to avoid
         * creating a loop. We only want to change the pointer of other
@@ -2910,16 +2930,64 @@ static void change_parent_backing_link(BlockDriverState *from,
            }
        }
        if (to_c) {
            return false;
        }
    }

    return true;
}

void bdrv_replace_node(BlockDriverState *from, BlockDriverState *to,
                       Error **errp)
{
    BdrvChild *c, *next;
    GSList *list = NULL, *p;
    uint64_t old_perm, old_shared;
    uint64_t perm = 0, shared = BLK_PERM_ALL;
    int ret;

    assert(!atomic_read(&from->in_flight));
    assert(!atomic_read(&to->in_flight));

    /* Make sure that @from doesn't go away until we have successfully attached
     * all of its parents to @to. */
    bdrv_ref(from);

    /* Put all parents into @list and calculate their cumulative permissions */
    QLIST_FOREACH_SAFE(c, &from->parents, next_parent, next) {
        if (!should_update_child(c, to)) {
            continue;
        }
        list = g_slist_prepend(list, c);
        perm |= c->perm;
        shared &= c->shared_perm;
    }

    /* Check whether the required permissions can be granted on @to, ignoring
     * all BdrvChild in @list so that they can't block themselves. */
    ret = bdrv_check_update_perm(to, perm, shared, list, errp);
    if (ret < 0) {
        bdrv_abort_perm_update(to);
        goto out;
    }

    /* Now actually perform the change. We performed the permission check for
     * all elements of @list at once, so set the permissions all at once at the
     * very end. */
    for (p = list; p != NULL; p = p->next) {
        c = p->data;

        bdrv_ref(to);
        /* FIXME Are we sure that bdrv_replace_child() can't run into
         * &error_abort because of permissions? */
        bdrv_replace_child(c, to, true);
        bdrv_replace_child_noperm(c, to);
        bdrv_unref(from);
    }

    bdrv_get_cumulative_perm(to, &old_perm, &old_shared);
    bdrv_set_perm(to, old_perm | perm, old_shared | shared);

out:
    g_slist_free(list);
    bdrv_unref(from);
}

/*
@@ -2943,16 +3011,18 @@ void bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top,
{
    Error *local_err = NULL;

    assert(!atomic_read(&bs_top->in_flight));
    assert(!atomic_read(&bs_new->in_flight));

    bdrv_set_backing_hd(bs_new, bs_top, &local_err);
    if (local_err) {
        error_propagate(errp, local_err);
        goto out;
    }

    change_parent_backing_link(bs_top, bs_new);
    bdrv_replace_node(bs_top, bs_new, &local_err);
    if (local_err) {
        error_propagate(errp, local_err);
        bdrv_set_backing_hd(bs_new, NULL, &error_abort);
        goto out;
    }

    /* bs_new is now referenced by its new parents, we don't need the
     * additional reference any more. */
@@ -2960,18 +3030,6 @@ out:
    bdrv_unref(bs_new);
}

void bdrv_replace_in_backing_chain(BlockDriverState *old, BlockDriverState *new)
{
    assert(!bdrv_requests_pending(old));
    assert(!bdrv_requests_pending(new));

    bdrv_ref(old);

    change_parent_backing_link(old, new);

    bdrv_unref(old);
}

static void bdrv_delete(BlockDriverState *bs)
{
    assert(!bs->job);
+6 −1
Original line number Diff line number Diff line
@@ -213,7 +213,12 @@ BlockBackend *blk_new_open(const char *filename, const char *reference,
    }

    blk->root = bdrv_root_attach_child(bs, "root", &child_root,
                                       perm, BLK_PERM_ALL, blk, &error_abort);
                                       perm, BLK_PERM_ALL, blk, errp);
    if (!blk->root) {
        bdrv_unref(bs);
        blk_unref(blk);
        return NULL;
    }

    return blk;
}
+15 −3
Original line number Diff line number Diff line
@@ -316,8 +316,20 @@ void commit_start(const char *job_id, BlockDriverState *bs,
        goto fail;
    }

    bdrv_set_backing_hd(commit_top_bs, top, &error_abort);
    bdrv_set_backing_hd(overlay_bs, commit_top_bs, &error_abort);
    bdrv_set_backing_hd(commit_top_bs, top, &local_err);
    if (local_err) {
        bdrv_unref(commit_top_bs);
        commit_top_bs = NULL;
        error_propagate(errp, local_err);
        goto fail;
    }
    bdrv_set_backing_hd(overlay_bs, commit_top_bs, &local_err);
    if (local_err) {
        bdrv_unref(commit_top_bs);
        commit_top_bs = NULL;
        error_propagate(errp, local_err);
        goto fail;
    }

    s->commit_top_bs = commit_top_bs;
    bdrv_unref(commit_top_bs);
@@ -364,7 +376,7 @@ void commit_start(const char *job_id, BlockDriverState *bs,

    /* Required permissions are already taken with block_job_add_bdrv() */
    s->top = blk_new(0, BLK_PERM_ALL);
    blk_insert_bs(s->top, top, errp);
    ret = blk_insert_bs(s->top, top, errp);
    if (ret < 0) {
        goto fail;
    }
+58 −69
Original line number Diff line number Diff line
@@ -12,6 +12,7 @@
#include "block/block_int.h"
#include "qapi/error.h"
#include "qapi/qmp/qerror.h"
#include "qapi/util.h"
#include "qemu/uri.h"
#include "qemu/error-report.h"
#include "qemu/cutils.h"
@@ -151,7 +152,7 @@ static QemuOptsList runtime_type_opts = {
        {
            .name = GLUSTER_OPT_TYPE,
            .type = QEMU_OPT_STRING,
            .help = "tcp|unix",
            .help = "inet|unix",
        },
        { /* end of list */ }
    },
@@ -170,14 +171,14 @@ static QemuOptsList runtime_unix_opts = {
    },
};

static QemuOptsList runtime_tcp_opts = {
    .name = "gluster_tcp",
    .head = QTAILQ_HEAD_INITIALIZER(runtime_tcp_opts.head),
static QemuOptsList runtime_inet_opts = {
    .name = "gluster_inet",
    .head = QTAILQ_HEAD_INITIALIZER(runtime_inet_opts.head),
    .desc = {
        {
            .name = GLUSTER_OPT_TYPE,
            .type = QEMU_OPT_STRING,
            .help = "tcp|unix",
            .help = "inet|unix",
        },
        {
            .name = GLUSTER_OPT_HOST,
@@ -320,7 +321,7 @@ static int parse_volume_options(BlockdevOptionsGluster *gconf, char *path)
static int qemu_gluster_parse_uri(BlockdevOptionsGluster *gconf,
                                  const char *filename)
{
    GlusterServer *gsconf;
    SocketAddressFlat *gsconf;
    URI *uri;
    QueryParams *qp = NULL;
    bool is_unix = false;
@@ -331,19 +332,19 @@ static int qemu_gluster_parse_uri(BlockdevOptionsGluster *gconf,
        return -EINVAL;
    }

    gconf->server = g_new0(GlusterServerList, 1);
    gconf->server->value = gsconf = g_new0(GlusterServer, 1);
    gconf->server = g_new0(SocketAddressFlatList, 1);
    gconf->server->value = gsconf = g_new0(SocketAddressFlat, 1);

    /* transport */
    if (!uri->scheme || !strcmp(uri->scheme, "gluster")) {
        gsconf->type = GLUSTER_TRANSPORT_TCP;
        gsconf->type = SOCKET_ADDRESS_FLAT_TYPE_INET;
    } else if (!strcmp(uri->scheme, "gluster+tcp")) {
        gsconf->type = GLUSTER_TRANSPORT_TCP;
        gsconf->type = SOCKET_ADDRESS_FLAT_TYPE_INET;
    } else if (!strcmp(uri->scheme, "gluster+unix")) {
        gsconf->type = GLUSTER_TRANSPORT_UNIX;
        gsconf->type = SOCKET_ADDRESS_FLAT_TYPE_UNIX;
        is_unix = true;
    } else if (!strcmp(uri->scheme, "gluster+rdma")) {
        gsconf->type = GLUSTER_TRANSPORT_TCP;
        gsconf->type = SOCKET_ADDRESS_FLAT_TYPE_INET;
        error_report("Warning: rdma feature is not supported, falling "
                     "back to tcp");
    } else {
@@ -373,11 +374,11 @@ static int qemu_gluster_parse_uri(BlockdevOptionsGluster *gconf,
        }
        gsconf->u.q_unix.path = g_strdup(qp->p[0].value);
    } else {
        gsconf->u.tcp.host = g_strdup(uri->server ? uri->server : "localhost");
        gsconf->u.inet.host = g_strdup(uri->server ? uri->server : "localhost");
        if (uri->port) {
            gsconf->u.tcp.port = g_strdup_printf("%d", uri->port);
            gsconf->u.inet.port = g_strdup_printf("%d", uri->port);
        } else {
            gsconf->u.tcp.port = g_strdup_printf("%d", GLUSTER_DEFAULT_PORT);
            gsconf->u.inet.port = g_strdup_printf("%d", GLUSTER_DEFAULT_PORT);
        }
    }

@@ -395,7 +396,7 @@ static struct glfs *qemu_gluster_glfs_init(BlockdevOptionsGluster *gconf,
    struct glfs *glfs;
    int ret;
    int old_errno;
    GlusterServerList *server;
    SocketAddressFlatList *server;
    unsigned long long port;

    glfs = glfs_find_preopened(gconf->volume);
@@ -411,21 +412,19 @@ static struct glfs *qemu_gluster_glfs_init(BlockdevOptionsGluster *gconf,
    glfs_set_preopened(gconf->volume, glfs);

    for (server = gconf->server; server; server = server->next) {
        if (server->value->type  == GLUSTER_TRANSPORT_UNIX) {
            ret = glfs_set_volfile_server(glfs,
                                   GlusterTransport_lookup[server->value->type],
        if (server->value->type  == SOCKET_ADDRESS_FLAT_TYPE_UNIX) {
            ret = glfs_set_volfile_server(glfs, "unix",
                                   server->value->u.q_unix.path, 0);
        } else {
            if (parse_uint_full(server->value->u.tcp.port, &port, 10) < 0 ||
            if (parse_uint_full(server->value->u.inet.port, &port, 10) < 0 ||
                port > 65535) {
                error_setg(errp, "'%s' is not a valid port number",
                           server->value->u.tcp.port);
                           server->value->u.inet.port);
                errno = EINVAL;
                goto out;
            }
            ret = glfs_set_volfile_server(glfs,
                                   GlusterTransport_lookup[server->value->type],
                                   server->value->u.tcp.host,
            ret = glfs_set_volfile_server(glfs, "tcp",
                                   server->value->u.inet.host,
                                   (int)port);
        }

@@ -444,13 +443,13 @@ static struct glfs *qemu_gluster_glfs_init(BlockdevOptionsGluster *gconf,
        error_setg(errp, "Gluster connection for volume %s, path %s failed"
                         " to connect", gconf->volume, gconf->path);
        for (server = gconf->server; server; server = server->next) {
            if (server->value->type  == GLUSTER_TRANSPORT_UNIX) {
            if (server->value->type  == SOCKET_ADDRESS_FLAT_TYPE_UNIX) {
                error_append_hint(errp, "hint: failed on socket %s ",
                                  server->value->u.q_unix.path);
            } else {
                error_append_hint(errp, "hint: failed on host %s and port %s ",
                                  server->value->u.tcp.host,
                                  server->value->u.tcp.port);
                                  server->value->u.inet.host,
                                  server->value->u.inet.port);
            }
        }

@@ -474,23 +473,6 @@ out:
    return NULL;
}

static int qapi_enum_parse(const char *opt)
{
    int i;

    if (!opt) {
        return GLUSTER_TRANSPORT__MAX;
    }

    for (i = 0; i < GLUSTER_TRANSPORT__MAX; i++) {
        if (!strcmp(opt, GlusterTransport_lookup[i])) {
            return i;
        }
    }

    return i;
}

/*
 * Convert the json formatted command line into qapi.
*/
@@ -498,8 +480,8 @@ static int qemu_gluster_parse_json(BlockdevOptionsGluster *gconf,
                                  QDict *options, Error **errp)
{
    QemuOpts *opts;
    GlusterServer *gsconf;
    GlusterServerList *curr = NULL;
    SocketAddressFlat *gsconf = NULL;
    SocketAddressFlatList *curr = NULL;
    QDict *backing_options = NULL;
    Error *local_err = NULL;
    char *str = NULL;
@@ -547,25 +529,31 @@ static int qemu_gluster_parse_json(BlockdevOptionsGluster *gconf,
        }

        ptr = qemu_opt_get(opts, GLUSTER_OPT_TYPE);
        gsconf = g_new0(GlusterServer, 1);
        gsconf->type = qapi_enum_parse(ptr);
        if (!ptr) {
            error_setg(&local_err, QERR_MISSING_PARAMETER, GLUSTER_OPT_TYPE);
            error_append_hint(&local_err, GERR_INDEX_HINT, i);
            goto out;

        }
        if (gsconf->type == GLUSTER_TRANSPORT__MAX) {
            error_setg(&local_err, QERR_INVALID_PARAMETER_VALUE,
                       GLUSTER_OPT_TYPE, "tcp or unix");
        gsconf = g_new0(SocketAddressFlat, 1);
        if (!strcmp(ptr, "tcp")) {
            ptr = "inet";       /* accept legacy "tcp" */
        }
        gsconf->type = qapi_enum_parse(SocketAddressFlatType_lookup, ptr,
                                       SOCKET_ADDRESS_FLAT_TYPE__MAX, -1,
                                       &local_err);
        if (local_err) {
            error_append_hint(&local_err,
                              "Parameter '%s' may be 'inet' or 'unix'\n",
                              GLUSTER_OPT_TYPE);
            error_append_hint(&local_err, GERR_INDEX_HINT, i);
            goto out;
        }
        qemu_opts_del(opts);

        if (gsconf->type == GLUSTER_TRANSPORT_TCP) {
            /* create opts info from runtime_tcp_opts list */
            opts = qemu_opts_create(&runtime_tcp_opts, NULL, 0, &error_abort);
        if (gsconf->type == SOCKET_ADDRESS_FLAT_TYPE_INET) {
            /* create opts info from runtime_inet_opts list */
            opts = qemu_opts_create(&runtime_inet_opts, NULL, 0, &error_abort);
            qemu_opts_absorb_qdict(opts, backing_options, &local_err);
            if (local_err) {
                goto out;
@@ -578,7 +566,7 @@ static int qemu_gluster_parse_json(BlockdevOptionsGluster *gconf,
                error_append_hint(&local_err, GERR_INDEX_HINT, i);
                goto out;
            }
            gsconf->u.tcp.host = g_strdup(ptr);
            gsconf->u.inet.host = g_strdup(ptr);
            ptr = qemu_opt_get(opts, GLUSTER_OPT_PORT);
            if (!ptr) {
                error_setg(&local_err, QERR_MISSING_PARAMETER,
@@ -586,28 +574,28 @@ static int qemu_gluster_parse_json(BlockdevOptionsGluster *gconf,
                error_append_hint(&local_err, GERR_INDEX_HINT, i);
                goto out;
            }
            gsconf->u.tcp.port = g_strdup(ptr);
            gsconf->u.inet.port = g_strdup(ptr);

            /* defend for unsupported fields in InetSocketAddress,
             * i.e. @ipv4, @ipv6  and @to
             */
            ptr = qemu_opt_get(opts, GLUSTER_OPT_TO);
            if (ptr) {
                gsconf->u.tcp.has_to = true;
                gsconf->u.inet.has_to = true;
            }
            ptr = qemu_opt_get(opts, GLUSTER_OPT_IPV4);
            if (ptr) {
                gsconf->u.tcp.has_ipv4 = true;
                gsconf->u.inet.has_ipv4 = true;
            }
            ptr = qemu_opt_get(opts, GLUSTER_OPT_IPV6);
            if (ptr) {
                gsconf->u.tcp.has_ipv6 = true;
                gsconf->u.inet.has_ipv6 = true;
            }
            if (gsconf->u.tcp.has_to) {
            if (gsconf->u.inet.has_to) {
                error_setg(&local_err, "Parameter 'to' not supported");
                goto out;
            }
            if (gsconf->u.tcp.has_ipv4 || gsconf->u.tcp.has_ipv6) {
            if (gsconf->u.inet.has_ipv4 || gsconf->u.inet.has_ipv6) {
                error_setg(&local_err, "Parameters 'ipv4/ipv6' not supported");
                goto out;
            }
@@ -632,16 +620,18 @@ static int qemu_gluster_parse_json(BlockdevOptionsGluster *gconf,
        }

        if (gconf->server == NULL) {
            gconf->server = g_new0(GlusterServerList, 1);
            gconf->server = g_new0(SocketAddressFlatList, 1);
            gconf->server->value = gsconf;
            curr = gconf->server;
        } else {
            curr->next = g_new0(GlusterServerList, 1);
            curr->next = g_new0(SocketAddressFlatList, 1);
            curr->next->value = gsconf;
            curr = curr->next;
        }
        gsconf = NULL;

        qdict_del(backing_options, str);
        QDECREF(backing_options);
        backing_options = NULL;
        g_free(str);
        str = NULL;
    }
@@ -650,11 +640,10 @@ static int qemu_gluster_parse_json(BlockdevOptionsGluster *gconf,

out:
    error_propagate(errp, local_err);
    qapi_free_SocketAddressFlat(gsconf);
    qemu_opts_del(opts);
    if (str) {
        qdict_del(backing_options, str);
    g_free(str);
    }
    QDECREF(backing_options);
    errno = EINVAL;
    return -errno;
}
@@ -683,7 +672,7 @@ static struct glfs *qemu_gluster_init(BlockdevOptionsGluster *gconf,
                             "file.volume=testvol,file.path=/path/a.qcow2"
                             "[,file.debug=9]"
                             "[,file.logfile=/path/filename.log],"
                             "file.server.0.type=tcp,"
                             "file.server.0.type=inet,"
                             "file.server.0.host=1.2.3.4,"
                             "file.server.0.port=24007,"
                             "file.server.1.transport=unix,"
+22 −13
Original line number Diff line number Diff line
@@ -509,6 +509,13 @@ static void mirror_exit(BlockJob *job, void *opaque)
     * block_job_completed(). */
    bdrv_ref(src);
    bdrv_ref(mirror_top_bs);
    bdrv_ref(target_bs);

    /* Remove target parent that still uses BLK_PERM_WRITE/RESIZE before
     * inserting target_bs at s->to_replace, where we might not be able to get
     * these permissions. */
    blk_unref(s->target);
    s->target = NULL;

    /* We don't access the source any more. Dropping any WRITE/RESIZE is
     * required before it could become a backing file of target_bs. */
@@ -543,8 +550,12 @@ static void mirror_exit(BlockJob *job, void *opaque)
        /* The mirror job has no requests in flight any more, but we need to
         * drain potential other users of the BDS before changing the graph. */
        bdrv_drained_begin(target_bs);
        bdrv_replace_in_backing_chain(to_replace, target_bs);
        bdrv_replace_node(to_replace, target_bs, &local_err);
        bdrv_drained_end(target_bs);
        if (local_err) {
            error_report_err(local_err);
            data->ret = -EPERM;
        }
    }
    if (s->to_replace) {
        bdrv_op_unblock_all(s->to_replace, s->replace_blocker);
@@ -555,19 +566,19 @@ static void mirror_exit(BlockJob *job, void *opaque)
        aio_context_release(replace_aio_context);
    }
    g_free(s->replaces);
    blk_unref(s->target);
    s->target = NULL;
    bdrv_unref(target_bs);

    /* Remove the mirror filter driver from the graph. Before this, get rid of
     * the blockers on the intermediate nodes so that the resulting state is
     * valid. */
     * valid. Also give up permissions on mirror_top_bs->backing, which might
     * block the removal. */
    block_job_remove_all_bdrv(job);
    bdrv_replace_in_backing_chain(mirror_top_bs, backing_bs(mirror_top_bs));
    bdrv_child_set_perm(mirror_top_bs->backing, 0, BLK_PERM_ALL);
    bdrv_replace_node(mirror_top_bs, backing_bs(mirror_top_bs), &error_abort);

    /* We just changed the BDS the job BB refers to (with either or both of the
     * bdrv_replace_in_backing_chain() calls), so switch the BB back so the
     * cleanup does the right thing. We don't need any permissions any more
     * now. */
     * bdrv_replace_node() calls), so switch the BB back so the cleanup does
     * the right thing. We don't need any permissions any more now. */
    blk_remove_bs(job->blk);
    blk_set_perm(job->blk, 0, BLK_PERM_ALL, &error_abort);
    blk_insert_bs(job->blk, mirror_top_bs, &error_abort);
@@ -1189,10 +1200,7 @@ static void mirror_start_job(const char *job_id, BlockDriverState *bs,

    s->dirty_bitmap = bdrv_create_dirty_bitmap(bs, granularity, NULL, errp);
    if (!s->dirty_bitmap) {
        g_free(s->replaces);
        blk_unref(s->target);
        block_job_unref(&s->common);
        return;
        goto fail;
    }

    /* Required permissions are already taken with blk_new() */
@@ -1228,7 +1236,8 @@ fail:
        block_job_unref(&s->common);
    }

    bdrv_replace_in_backing_chain(mirror_top_bs, backing_bs(mirror_top_bs));
    bdrv_child_set_perm(mirror_top_bs->backing, 0, BLK_PERM_ALL);
    bdrv_replace_node(mirror_top_bs, backing_bs(mirror_top_bs), &error_abort);
}

void mirror_start(const char *job_id, BlockDriverState *bs,
Loading