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