Commit 190b9a8b authored by Changlong Xie's avatar Changlong Xie Committed by Stefan Hajnoczi
Browse files

replication: Introduce new APIs to do replication operation



This commit introduces six replication interfaces(for block, network etc).
Firstly we can use replication_(new/remove) to create/destroy replication
instances, then in migration we can use replication_(start/stop/do_checkpoint
/get_error)_all to handle all replication operations. More detail please
refer to replication.h

Signed-off-by: default avatarWen Congyang <wency@cn.fujitsu.com>
Signed-off-by: default avatarChanglong Xie <xiecl.fnst@cn.fujitsu.com>
Signed-off-by: default avatarWang WeiWei <wangww.fnst@cn.fujitsu.com>
Signed-off-by: default avatarzhanghailiang <zhang.zhanghailiang@huawei.com>
Signed-off-by: default avatarGonglei <arei.gonglei@huawei.com>
Message-id: 1469602913-20979-9-git-send-email-xiecl.fnst@cn.fujitsu.com
Signed-off-by: default avatarStefan Hajnoczi <stefanha@redhat.com>
parent a6b1d4c0
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@ block-obj-$(CONFIG_POSIX) += aio-posix.o
block-obj-$(CONFIG_WIN32) += aio-win32.o
block-obj-y += block/
block-obj-y += qemu-io-cmds.o
block-obj-$(CONFIG_REPLICATION) += replication.o

block-obj-m = block/

+13 −0
Original line number Diff line number Diff line
@@ -2162,6 +2162,19 @@
            'server': ['GlusterServer'],
            '*debug-level': 'int' } }

##
# @ReplicationMode
#
# An enumeration of replication modes.
#
# @primary: Primary mode, the vm's state will be sent to secondary QEMU.
#
# @secondary: Secondary mode, receive the vm's state from primary QEMU.
#
# Since: 2.8
##
{ 'enum' : 'ReplicationMode', 'data' : [ 'primary', 'secondary' ] }

##
# @BlockdevOptions
#

replication.c

0 → 100644
+107 −0
Original line number Diff line number Diff line
/*
 * Replication filter
 *
 * Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD.
 * Copyright (c) 2016 Intel Corporation
 * Copyright (c) 2016 FUJITSU LIMITED
 *
 * Author:
 *   Changlong Xie <xiecl.fnst@cn.fujitsu.com>
 *
 * This work is licensed under the terms of the GNU GPL, version 2 or later.
 * See the COPYING file in the top-level directory.
 */

#include "qemu/osdep.h"
#include "qapi/error.h"
#include "replication.h"

static QLIST_HEAD(, ReplicationState) replication_states;

ReplicationState *replication_new(void *opaque, ReplicationOps *ops)
{
    ReplicationState *rs;

    assert(ops != NULL);
    rs = g_new0(ReplicationState, 1);
    rs->opaque = opaque;
    rs->ops = ops;
    QLIST_INSERT_HEAD(&replication_states, rs, node);

    return rs;
}

void replication_remove(ReplicationState *rs)
{
    if (rs) {
        QLIST_REMOVE(rs, node);
        g_free(rs);
    }
}

/*
 * The caller of the function MUST make sure vm stopped
 */
void replication_start_all(ReplicationMode mode, Error **errp)
{
    ReplicationState *rs, *next;
    Error *local_err = NULL;

    QLIST_FOREACH_SAFE(rs, &replication_states, node, next) {
        if (rs->ops && rs->ops->start) {
            rs->ops->start(rs, mode, &local_err);
        }
        if (local_err) {
            error_propagate(errp, local_err);
            return;
        }
    }
}

void replication_do_checkpoint_all(Error **errp)
{
    ReplicationState *rs, *next;
    Error *local_err = NULL;

    QLIST_FOREACH_SAFE(rs, &replication_states, node, next) {
        if (rs->ops && rs->ops->checkpoint) {
            rs->ops->checkpoint(rs, &local_err);
        }
        if (local_err) {
            error_propagate(errp, local_err);
            return;
        }
    }
}

void replication_get_error_all(Error **errp)
{
    ReplicationState *rs, *next;
    Error *local_err = NULL;

    QLIST_FOREACH_SAFE(rs, &replication_states, node, next) {
        if (rs->ops && rs->ops->get_error) {
            rs->ops->get_error(rs, &local_err);
        }
        if (local_err) {
            error_propagate(errp, local_err);
            return;
        }
    }
}

void replication_stop_all(bool failover, Error **errp)
{
    ReplicationState *rs, *next;
    Error *local_err = NULL;

    QLIST_FOREACH_SAFE(rs, &replication_states, node, next) {
        if (rs->ops && rs->ops->stop) {
            rs->ops->stop(rs, failover, &local_err);
        }
        if (local_err) {
            error_propagate(errp, local_err);
            return;
        }
    }
}

replication.h

0 → 100644
+174 −0
Original line number Diff line number Diff line
/*
 * Replication filter
 *
 * Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD.
 * Copyright (c) 2016 Intel Corporation
 * Copyright (c) 2016 FUJITSU LIMITED
 *
 * Author:
 *   Changlong Xie <xiecl.fnst@cn.fujitsu.com>
 *
 * This work is licensed under the terms of the GNU GPL, version 2 or later.
 * See the COPYING file in the top-level directory.
 */

#ifndef REPLICATION_H
#define REPLICATION_H

#include "qemu/queue.h"

typedef struct ReplicationOps ReplicationOps;
typedef struct ReplicationState ReplicationState;

/**
 * SECTION:replication.h
 * @title:Base Replication System
 * @short_description: interfaces for handling replication
 *
 * The Replication Model provides a framework for handling Replication
 *
 * <example>
 *   <title>How to use replication interfaces</title>
 *   <programlisting>
 * #include "replication.h"
 *
 * typedef struct BDRVReplicationState {
 *     ReplicationState *rs;
 * } BDRVReplicationState;
 *
 * static void replication_start(ReplicationState *rs, ReplicationMode mode,
 *                               Error **errp);
 * static void replication_do_checkpoint(ReplicationState *rs, Error **errp);
 * static void replication_get_error(ReplicationState *rs, Error **errp);
 * static void replication_stop(ReplicationState *rs, bool failover,
 *                              Error **errp);
 *
 * static ReplicationOps replication_ops = {
 *     .start = replication_start,
 *     .checkpoint = replication_do_checkpoint,
 *     .get_error = replication_get_error,
 *     .stop = replication_stop,
 * }
 *
 * static int replication_open(BlockDriverState *bs, QDict *options,
 *                             int flags, Error **errp)
 * {
 *     BDRVReplicationState *s = bs->opaque;
 *     s->rs = replication_new(bs, &replication_ops);
 *     return 0;
 * }
 *
 * static void replication_close(BlockDriverState *bs)
 * {
 *     BDRVReplicationState *s = bs->opaque;
 *     replication_remove(s->rs);
 * }
 *
 * BlockDriver bdrv_replication = {
 *     .format_name                = "replication",
 *     .protocol_name              = "replication",
 *     .instance_size              = sizeof(BDRVReplicationState),
 *
 *     .bdrv_open                  = replication_open,
 *     .bdrv_close                 = replication_close,
 * };
 *
 * static void bdrv_replication_init(void)
 * {
 *     bdrv_register(&bdrv_replication);
 * }
 *
 * block_init(bdrv_replication_init);
 *   </programlisting>
 * </example>
 *
 * We create an example about how to use replication interfaces in above.
 * Then in migration, we can use replication_(start/stop/do_checkpoint/
 * get_error)_all to handle all replication operations.
 */

/**
 * ReplicationState:
 * @opaque: opaque pointer value passed to this ReplicationState
 * @ops: replication operation of this ReplicationState
 * @node: node that we will insert into @replication_states QLIST
 */
struct ReplicationState {
    void *opaque;
    ReplicationOps *ops;
    QLIST_ENTRY(ReplicationState) node;
};

/**
 * ReplicationOps:
 * @start: callback to start replication
 * @stop: callback to stop replication
 * @checkpoint: callback to do checkpoint
 * @get_error: callback to check if error occurred during replication
 */
struct ReplicationOps {
    void (*start)(ReplicationState *rs, ReplicationMode mode, Error **errp);
    void (*stop)(ReplicationState *rs, bool failover, Error **errp);
    void (*checkpoint)(ReplicationState *rs, Error **errp);
    void (*get_error)(ReplicationState *rs, Error **errp);
};

/**
 * replication_new:
 * @opaque: opaque pointer value passed to ReplicationState
 * @ops: replication operation of the new relevant ReplicationState
 *
 * Called to create a new ReplicationState instance, and then insert it
 * into @replication_states QLIST
 *
 * Returns: the new ReplicationState instance
 */
ReplicationState *replication_new(void *opaque, ReplicationOps *ops);

/**
 * replication_remove:
 * @rs: the ReplicationState instance to remove
 *
 * Called to remove a ReplicationState instance, and then delete it from
 * @replication_states QLIST
 */
void replication_remove(ReplicationState *rs);

/**
 * replication_start_all:
 * @mode: replication mode that could be "primary" or "secondary"
 * @errp: returns an error if this function fails
 *
 * Start replication, called in migration/checkpoint thread
 *
 * Note: the caller of the function MUST make sure vm stopped
 */
void replication_start_all(ReplicationMode mode, Error **errp);

/**
 * replication_do_checkpoint_all:
 * @errp: returns an error if this function fails
 *
 * This interface is called after all VM state is transferred to Secondary QEMU
 */
void replication_do_checkpoint_all(Error **errp);

/**
 * replication_get_error_all:
 * @errp: returns an error if this function fails
 *
 * This interface is called to check if error occurred during replication
 */
void replication_get_error_all(Error **errp);

/**
 * replication_stop_all:
 * @failover: boolean value that indicates if we need do failover or not
 * @errp: returns an error if this function fails
 *
 * It is called on failover. The vm should be stopped before calling it, if you
 * use this API to shutdown the guest, or other things except failover
 */
void replication_stop_all(bool failover, Error **errp);

#endif /* REPLICATION_H */