Commit 1de6b45f authored by Kevin Wolf's avatar Kevin Wolf
Browse files

block: bdrv_reopen() with backing file in different AioContext



This patch allows bdrv_reopen() (and therefore the x-blockdev-reopen QMP
command) to attach a node as the new backing file even if the node is in
a different AioContext than the parent if one of both nodes can be moved
to the AioContext of the other node.

Signed-off-by: default avatarKevin Wolf <kwolf@redhat.com>
Tested-by: default avatarPeter Krempa <pkrempa@redhat.com>
Message-Id: <20200306141413.30705-3-kwolf@redhat.com>
Reviewed-by: default avatarAlberto Garcia <berto@igalia.com>
Signed-off-by: default avatarKevin Wolf <kwolf@redhat.com>
parent 97518e11
Loading
Loading
Loading
Loading
+26 −6
Original line number Diff line number Diff line
@@ -3787,6 +3787,29 @@ static void bdrv_reopen_perm(BlockReopenQueue *q, BlockDriverState *bs,
    *shared = cumulative_shared_perms;
}

static bool bdrv_reopen_can_attach(BlockDriverState *parent,
                                   BdrvChild *child,
                                   BlockDriverState *new_child,
                                   Error **errp)
{
    AioContext *parent_ctx = bdrv_get_aio_context(parent);
    AioContext *child_ctx = bdrv_get_aio_context(new_child);
    GSList *ignore;
    bool ret;

    ignore = g_slist_prepend(NULL, child);
    ret = bdrv_can_set_aio_context(new_child, parent_ctx, &ignore, NULL);
    g_slist_free(ignore);
    if (ret) {
        return ret;
    }

    ignore = g_slist_prepend(NULL, child);
    ret = bdrv_can_set_aio_context(parent, child_ctx, &ignore, errp);
    g_slist_free(ignore);
    return ret;
}

/*
 * Take a BDRVReopenState and check if the value of 'backing' in the
 * reopen_state->options QDict is valid or not.
@@ -3838,14 +3861,11 @@ static int bdrv_reopen_parse_backing(BDRVReopenState *reopen_state,
    }

    /*
     * TODO: before removing the x- prefix from x-blockdev-reopen we
     * should move the new backing file into the right AioContext
     * instead of returning an error.
     * Check AioContext compatibility so that the bdrv_set_backing_hd() call in
     * bdrv_reopen_commit() won't fail.
     */
    if (new_backing_bs) {
        if (bdrv_get_aio_context(new_backing_bs) != bdrv_get_aio_context(bs)) {
            error_setg(errp, "Cannot use a new backing file "
                       "with a different AioContext");
        if (!bdrv_reopen_can_attach(bs, bs->backing, new_backing_bs, errp)) {
            return -EINVAL;
        }
    }
+3 −5
Original line number Diff line number Diff line
@@ -1015,18 +1015,16 @@ class TestBlockdevReopen(iotests.QMPTestCase):
    # neither of them can switch to the other AioContext
    def test_iothreads_error(self):
        self.run_test_iothreads('iothread0', 'iothread1',
                                "Cannot use a new backing file with a different AioContext")
                                "Cannot change iothread of active block backend")

    def test_iothreads_compatible_users(self):
        self.run_test_iothreads('iothread0', 'iothread0')

    def test_iothreads_switch_backing(self):
        self.run_test_iothreads('iothread0', None,
                                "Cannot use a new backing file with a different AioContext")
        self.run_test_iothreads('iothread0', None)

    def test_iothreads_switch_overlay(self):
        self.run_test_iothreads(None, 'iothread0',
                                "Cannot use a new backing file with a different AioContext")
        self.run_test_iothreads(None, 'iothread0')

if __name__ == '__main__':
    iotests.main(supported_fmts=["qcow2"],