mirror of https://gitee.com/openkylin/qemu.git
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: Wen Congyang <wency@cn.fujitsu.com> Signed-off-by: Changlong Xie <xiecl.fnst@cn.fujitsu.com> Signed-off-by: Wang WeiWei <wangww.fnst@cn.fujitsu.com> Signed-off-by: zhanghailiang <zhang.zhanghailiang@huawei.com> Signed-off-by: Gonglei <arei.gonglei@huawei.com> Message-id: 1469602913-20979-9-git-send-email-xiecl.fnst@cn.fujitsu.com Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
parent
a6b1d4c081
commit
190b9a8b55
|
@ -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/
|
||||
|
||||
|
|
|
@ -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
|
||||
#
|
||||
|
|
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,174 @@
|
|||
/*
|
||||
* 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 */
|
Loading…
Reference in New Issue