diff mbox

[v17,6/8] Introduce new APIs to do replication operation

Message ID 1460362979-15146-7-git-send-email-xiecl.fnst@cn.fujitsu.com (mailing list archive)
State New, archived
Headers show

Commit Message

Changlong Xie April 11, 2016, 8:22 a.m. UTC
Signed-off-by: Wen Congyang <wency@cn.fujitsu.com>
Signed-off-by: zhanghailiang <zhang.zhanghailiang@huawei.com>
Signed-off-by: Gonglei <arei.gonglei@huawei.com>
Signed-off-by: Changlong Xie <xiecl.fnst@cn.fujitsu.com>
---
 Makefile.objs        |   1 +
 qapi/block-core.json |  13 ++++
 replication.c        |  96 ++++++++++++++++++++++++++++
 replication.h        | 175 +++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 285 insertions(+)
 create mode 100644 replication.c
 create mode 100644 replication.h

Comments

Stefan Hajnoczi April 13, 2016, 12:47 p.m. UTC | #1
On Mon, Apr 11, 2016 at 04:22:57PM +0800, Changlong Xie wrote:
> +/*
> + * The caller of the function MUST make sure vm stopped
> + */
> +void replication_start_all(ReplicationMode mode, Error **errp)
> +{
> +    ReplicationState *rs, *next;
> +
> +    QLIST_FOREACH_SAFE(rs, &replication_states, node, next) {
> +        if (rs->ops && rs->ops->start) {
> +            rs->ops->start(rs, mode, errp);
> +        }
> +        if (errp && *errp) {
> +            return;
> +        }

This function returns immediately on error if the caller provided errp.
It continues if the caller did not provide errp.

I'm not sure if you wanted this difference in behavior.

The following always returns immediately on error, even when the caller
did not provide errp:

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;
        }
> +/**
> + * SECTION:replication.h
> + * @title:Base Replication System
> + * @short_description: interfaces for handle replication
> + *
> + * The Replication Model provides a framework for handle Replication

s/handle/handling/
Changlong Xie April 14, 2016, 1:47 a.m. UTC | #2
On 04/13/2016 08:47 PM, Stefan Hajnoczi wrote:
> On Mon, Apr 11, 2016 at 04:22:57PM +0800, Changlong Xie wrote:
>> +/*
>> + * The caller of the function MUST make sure vm stopped
>> + */
>> +void replication_start_all(ReplicationMode mode, Error **errp)
>> +{
>> +    ReplicationState *rs, *next;
>> +
>> +    QLIST_FOREACH_SAFE(rs, &replication_states, node, next) {
>> +        if (rs->ops && rs->ops->start) {
>> +            rs->ops->start(rs, mode, errp);
>> +        }
>> +        if (errp && *errp) {
>> +            return;
>> +        }
>
> This function returns immediately on error if the caller provided errp.
> It continues if the caller did not provide errp.
>
> I'm not sure if you wanted this difference in behavior.
>
> The following always returns immediately on error, even when the caller
> did not provide errp:
>

I just notice that, if errp == NULL and error happens in 
rs->ops->{start,...}, we could never detect it. I'll check all 
replication callbacks carefully

Thanks
	-Xie
> 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;
>          }
>> +/**
>> + * SECTION:replication.h
>> + * @title:Base Replication System
>> + * @short_description: interfaces for handle replication
>> + *
>> + * The Replication Model provides a framework for handle Replication
>
> s/handle/handling/
>
diff mbox

Patch

diff --git a/Makefile.objs b/Makefile.objs
index 8f705f6..30d403f 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -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-y += replication.o
 
 block-obj-m = block/
 
diff --git a/qapi/block-core.json b/qapi/block-core.json
index 98a20d2..e56cdf4 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -2032,6 +2032,19 @@ 
             '*read-pattern': 'QuorumReadPattern' } }
 
 ##
+# @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.7
+##
+{ 'enum' : 'ReplicationMode', 'data' : [ 'primary', 'secondary' ] }
+
+##
 # @BlockdevOptions
 #
 # Options for creating a block device.  Many options are available for all
diff --git a/replication.c b/replication.c
new file mode 100644
index 0000000..2f94d2a
--- /dev/null
+++ b/replication.c
@@ -0,0 +1,96 @@ 
+/*
+ * 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 "replication.h"
+
+static QLIST_HEAD(, ReplicationState) replication_states;
+
+ReplicationState *replication_new(void *opaque, ReplicationOps *ops)
+{
+    ReplicationState *rs;
+
+    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;
+
+    QLIST_FOREACH_SAFE(rs, &replication_states, node, next) {
+        if (rs->ops && rs->ops->start) {
+            rs->ops->start(rs, mode, errp);
+        }
+        if (errp && *errp) {
+            return;
+        }
+    }
+}
+
+void replication_do_checkpoint_all(Error **errp)
+{
+    ReplicationState *rs, *next;
+
+    QLIST_FOREACH_SAFE(rs, &replication_states, node, next) {
+        if (rs->ops && rs->ops->checkpoint) {
+            rs->ops->checkpoint(rs, errp);
+        }
+        if (errp && *errp) {
+            return;
+        }
+    }
+}
+
+void replication_get_error_all(Error **errp)
+{
+    ReplicationState *rs, *next;
+
+    QLIST_FOREACH_SAFE(rs, &replication_states, node, next) {
+        if (rs->ops && rs->ops->get_error) {
+            rs->ops->get_error(rs, errp);
+        }
+        if (errp && *errp) {
+            return;
+        }
+    }
+}
+
+void replication_stop_all(bool failover, Error **errp)
+{
+    ReplicationState *rs, *next;
+
+    QLIST_FOREACH_SAFE(rs, &replication_states, node, next) {
+        if (rs->ops && rs->ops->stop) {
+            rs->ops->stop(rs, failover, errp);
+        }
+        if (errp && *errp) {
+            return;
+        }
+    }
+}
diff --git a/replication.h b/replication.h
new file mode 100644
index 0000000..d09849a
--- /dev/null
+++ b/replication.h
@@ -0,0 +1,175 @@ 
+/*
+ * 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/osdep.h"
+#include "sysemu/sysemu.h"
+
+typedef struct ReplicationOps ReplicationOps;
+typedef struct ReplicationState ReplicationState;
+
+/**
+ * SECTION:replication.h
+ * @title:Base Replication System
+ * @short_description: interfaces for handle replication
+ *
+ * The Replication Model provides a framework for handle Replication
+ *
+ * <example>
+ *   <title>How to use replication interface</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 interface 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 */