[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[lvm-devel] [PATCH 06/23] Replicator: lvm2 support



Adding configure.in support for Replicators.
Adding basic lib lvm support for Replicators.
Adding flags REPLICATOR and REPLICATOR_LOG.
Adding segments SEG_REPLICATOR and SEG_REPLICATOR_DEV.
Adding basic methods for handling replicator metadata.

Signed-off-by: Zdenek Kabelac <zkabelac redhat com>
---
 configure.in                     |   17 +
 lib/Makefile.in                  |   10 +
 lib/commands/toolcontext.c       |    5 +
 lib/format_text/flags.c          |    2 +
 lib/metadata/lv_manip.c          |    1 +
 lib/metadata/merge.c             |   14 +
 lib/metadata/metadata-exported.h |   74 ++++-
 lib/metadata/replicator_manip.c  |  327 ++++++++++++++++
 lib/metadata/segtype.h           |    8 +
 lib/replicator/.exported_symbols |    1 +
 lib/replicator/Makefile.in       |   25 ++
 lib/replicator/replicator.c      |  790 ++++++++++++++++++++++++++++++++++++++
 12 files changed, 1273 insertions(+), 1 deletions(-)
 create mode 100644 lib/metadata/replicator_manip.c
 create mode 100644 lib/replicator/.exported_symbols
 create mode 100644 lib/replicator/Makefile.in
 create mode 100644 lib/replicator/replicator.c

diff --git a/configure.in b/configure.in
index b2a6e0c..dea653f 100644
--- a/configure.in
+++ b/configure.in
@@ -303,6 +303,21 @@ if test x$MIRRORS = xinternal; then
 fi
 
 ################################################################################
+dnl -- asynchronous volume replicator inclusion type
+AC_MSG_CHECKING(whether to include replicators)
+AC_ARG_WITH(replicators, AC_HELP_STRING([--with-replicators=TYPE],
+	[Replicator support: internal/shared/none [TYPE=none] ]),
+	[REPLICATORS=$withval], [REPLICATORS="none"])
+AC_MSG_RESULT($REPLICATORS)
+
+case "$REPLICATORS" in
+  none|shared) ;;
+  internal) AC_DEFINE([REPLICATOR_INTERNAL], 1,
+		[Define to 1 to include built-in support for replicators.]) ;;
+  *) AC_MSG_ERROR([--with-replicators parameter invalid ($REPLICATORS)]) ;;
+esac
+
+################################################################################
 dnl -- Disable readline
 AC_MSG_CHECKING(whether to enable readline)
 AC_ARG_ENABLE([readline],
@@ -1109,6 +1124,7 @@ AC_SUBST(LVM_PATCHLEVEL)
 AC_SUBST(LVM_RELEASE)
 AC_SUBST(LVM_RELEASE_DATE)
 AC_SUBST(MIRRORS)
+AC_SUBST(REPLICATORS)
 AC_SUBST(MSGFMT)
 AC_SUBST(PKGCONFIG)
 AC_SUBST(POOL)
@@ -1163,6 +1179,7 @@ lib/format1/Makefile
 lib/format_pool/Makefile
 lib/locking/Makefile
 lib/mirror/Makefile
+lib/replicator/Makefile
 lib/misc/lvm-version.h
 lib/snapshot/Makefile
 libdm/Makefile
diff --git a/lib/Makefile.in b/lib/Makefile.in
index 3498141..ae81040 100644
--- a/lib/Makefile.in
+++ b/lib/Makefile.in
@@ -32,6 +32,10 @@ ifeq ("@MIRRORS@", "shared")
   SUBDIRS += mirror
 endif
 
+ifeq ("@REPLICATORS@", "shared")
+  SUBDIRS += replicator
+endif
+
 SOURCES =\
 	activate/activate.c \
 	cache/lvmcache.c \
@@ -74,6 +78,7 @@ SOURCES =\
 	metadata/mirror.c \
 	metadata/pv_manip.c \
 	metadata/pv_map.c \
+	metadata/replicator_manip.c \
 	metadata/segtype.c \
 	metadata/snapshot_manip.c \
 	misc/crc.c \
@@ -129,6 +134,10 @@ ifeq ("@MIRRORS@", "internal")
   SOURCES += mirror/mirrored.c
 endif
 
+ifeq ("@REPLICATORS@", "internal")
+  SOURCES += replicator/replicator.c
+endif
+
 ifeq ("@DEVMAPPER@", "yes")
   SOURCES +=\
 	activate/dev_manager.c \
@@ -155,6 +164,7 @@ ifeq ($(MAKECMDGOALS),distclean)
 	format_pool \
 	snapshot \
 	mirror \
+	replicator \
 	locking
 endif
 
diff --git a/lib/commands/toolcontext.c b/lib/commands/toolcontext.c
index c780d26..890da3e 100644
--- a/lib/commands/toolcontext.c
+++ b/lib/commands/toolcontext.c
@@ -936,6 +936,11 @@ static int _init_segtypes(struct cmd_context *cmd)
 	dm_list_add(&cmd->segtypes, &segtype->list);
 #endif
 
+#ifdef REPLICATOR_INTERNAL
+	if (!init_replicator_segtype(&seglib))
+		return 0;
+#endif
+
 #ifdef HAVE_LIBDL
 	/* Load any formats in shared libs unless static */
 	if (!is_static() &&
diff --git a/lib/format_text/flags.c b/lib/format_text/flags.c
index a41dc1a..994adf2 100644
--- a/lib/format_text/flags.c
+++ b/lib/format_text/flags.c
@@ -67,6 +67,8 @@ static const struct flag _lv_flags[] = {
 	{PARTIAL_LV, NULL, 0},
 	{POSTORDER_FLAG, NULL, 0},
 	{VIRTUAL_ORIGIN, NULL, 0},
+	{REPLICATOR, NULL, 0},
+	{REPLICATOR_LOG, NULL, 0},
 	{0, NULL, 0}
 };
 
diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c
index de97341..5e4a674 100644
--- a/lib/metadata/lv_manip.c
+++ b/lib/metadata/lv_manip.c
@@ -2008,6 +2008,7 @@ struct logical_volume *alloc_lv(struct dm_pool *mem)
 	dm_list_init(&lv->segments);
 	dm_list_init(&lv->tags);
 	dm_list_init(&lv->segs_using_this_lv);
+	dm_list_init(&lv->rsites);
 
 	return lv;
 }
diff --git a/lib/metadata/merge.c b/lib/metadata/merge.c
index df90743..66ff57b 100644
--- a/lib/metadata/merge.c
+++ b/lib/metadata/merge.c
@@ -72,6 +72,8 @@ int check_lv_segments(struct logical_volume *lv, int complete_vg)
 	uint32_t area_multiplier, s;
 	struct seg_list *sl;
 	int error_count = 0;
+	struct replicator_site *rsite;
+	struct replicator_device *rdev;
 
 	dm_list_iterate_items(seg, &lv->segments) {
 		seg_count++;
@@ -213,6 +215,18 @@ int check_lv_segments(struct logical_volume *lv, int complete_vg)
 			if (lv == seg_lv(seg, s))
 				seg_found++;
 		}
+		if (seg_is_replicator_dev(seg)) {
+			dm_list_iterate_items(rsite, &seg->replicator->rsites) {
+				dm_list_iterate_items(rdev, &rsite->rdevices) {
+					if (lv == rdev->lv || lv == rdev->slog)
+						seg_found++;
+				}
+			}
+			if (lv == seg->replicator)
+				seg_found++;
+		}
+		if (seg_is_replicator(seg) && lv == seg->rlog_lv)
+				seg_found++;
 		if (seg->log_lv == lv)
 			seg_found++;
 		if (!seg_found) {
diff --git a/lib/metadata/metadata-exported.h b/lib/metadata/metadata-exported.h
index 3c5f8a3..37588aa 100644
--- a/lib/metadata/metadata-exported.h
+++ b/lib/metadata/metadata-exported.h
@@ -72,6 +72,9 @@
 
 #define MERGING			0x10000000U	/* LV SEG */
 
+#define REPLICATOR		0x20000000U	/* LV -internal use only for replicator */
+#define REPLICATOR_LOG		0x40000000U	/* LV -internal use only for replicator-dev */
+
 #define LVM_READ              	0x00000100U	/* LV VG */
 #define LVM_WRITE             	0x00000200U	/* LV VG */
 #define CLUSTERED         	0x00000400U	/* VG */
@@ -292,6 +295,45 @@ struct lv_segment_area {
 };
 
 struct segment_type;
+
+/* ++ Replicator datatypes */
+typedef enum {
+	REPLICATOR_STATE_PASSIVE,
+	REPLICATOR_STATE_ACTIVE,
+	NUM_REPLICATOR_STATE
+} replicator_state_t;
+
+struct replicator_site {
+	struct dm_list list;		/* Chained list of sites */
+	struct dm_list rdevices;	/* Device list */
+
+	struct logical_volume *replicator; /* Reference to replicator */
+
+	const char *name;               /* Site name */
+	const char *vg_name;		/* VG name */
+	struct volume_group *vg;        /* resolved vg  (activate/deactive) */
+	unsigned site_index;
+	replicator_state_t state;	/* Active or pasive state of site */
+	dm_replicator_mode_t op_mode;	/* Operation mode sync or async fail|warn|drop|stall */
+	uint64_t fall_behind_data;	/* Bytes */
+	uint32_t fall_behind_ios;	/* IO operations */
+	uint32_t fall_behind_timeout;	/* Seconds */
+};
+
+struct replicator_device {
+	struct dm_list list;		/* Chained list of devices from same site */
+
+	struct lv_segment *replicator_dev; /* Reference to replicator-dev segment */
+	struct replicator_site *rsite;	/* Reference to site parameters */
+
+	uint64_t device_index;
+	const char *name;		/* Device LV name */
+	struct logical_volume *lv;	/* LV from replicator site's VG */
+	struct logical_volume *slog;	/* Synclog lv from VG  */
+	const char *slog_name;		/* Debug - specify size of core synclog */
+};
+/* -- Replicator datatypes */
+
 struct lv_segment {
 	struct dm_list list;
 	struct logical_volume *lv;
@@ -310,7 +352,7 @@ struct lv_segment {
 	struct logical_volume *origin;
 	struct logical_volume *cow;
 	struct dm_list origin_list;
-	uint32_t region_size;	/* For mirrors - in sectors */
+	uint32_t region_size;	/* For mirrors, replicators - in sectors */
 	uint32_t extents_copied;
 	struct logical_volume *log_lv;
 	struct lv_segment *pvmove_source_seg;
@@ -319,6 +361,12 @@ struct lv_segment {
 	struct dm_list tags;
 
 	struct lv_segment_area *areas;
+
+	struct logical_volume *replicator;/* For replicator-devs - link to replicator LV */
+	struct logical_volume *rlog_lv;	/* For replicators */
+	const char *rlog_type;		/* For replicators */
+	uint64_t rdevice_index_highest;	/* For replicators */
+	unsigned rsite_index_highest;	/* For replicators */
 };
 
 #define seg_type(seg, s)	(seg)->areas[(s)].type
@@ -344,6 +392,9 @@ struct logical_volume {
 	struct dm_list snapshot_segs;
 	struct lv_segment *snapshot;
 
+	struct replicator_device *rdevice;/* For replicator-devs, rimages, slogs - reference to rdevice */
+	struct dm_list rsites;	/* For replicators - all sites */
+
 	struct dm_list segments;
 	struct dm_list tags;
 	struct dm_list segs_using_this_lv;
@@ -719,6 +770,27 @@ int reconfigure_mirror_images(struct lv_segment *mirrored_seg, uint32_t num_mirr
 int collapse_mirrored_lv(struct logical_volume *lv);
 int shift_mirror_images(struct lv_segment *mirrored_seg, unsigned mimage);
 
+/* ++  metadata/replicator_manip.c */
+int replicator_add_replicator_dev(struct logical_volume *replicator_lv,
+				  struct lv_segment *rdev_seg);
+struct logical_volume *replicator_remove_replicator_dev(struct lv_segment *rdev_seg);
+int replicator_add_rlog(struct lv_segment *replicator_seg, struct logical_volume *rlog_lv);
+struct logical_volume *replicator_remove_rlog(struct lv_segment *replicator_seg);
+
+int replicator_dev_add_slog(struct replicator_device *rdev, struct logical_volume *slog_lv);
+struct logical_volume *replicator_dev_remove_slog(struct replicator_device *rdev);
+int replicator_dev_add_rimage(struct replicator_device *rdev, struct logical_volume *lv);
+struct logical_volume *replicator_dev_remove_rimage(struct replicator_device *rdev);
+
+int lv_is_active_replicator_dev(const struct logical_volume *lv);
+int lv_is_replicator(const struct logical_volume *lv);
+int lv_is_replicator_dev(const struct logical_volume *lv);
+int lv_is_rimage(const struct logical_volume *lv);
+int lv_is_rlog(const struct logical_volume *lv);
+int lv_is_slog(const struct logical_volume *lv);
+struct logical_volume *first_replicator_dev(const struct logical_volume *lv);
+/* --  metadata/replicator_manip.c */
+
 struct logical_volume *find_pvmove_lv(struct volume_group *vg,
 				      struct device *dev, uint32_t lv_type);
 struct logical_volume *find_pvmove_lv_from_pvname(struct cmd_context *cmd,
diff --git a/lib/metadata/replicator_manip.c b/lib/metadata/replicator_manip.c
new file mode 100644
index 0000000..da189d6
--- /dev/null
+++ b/lib/metadata/replicator_manip.c
@@ -0,0 +1,327 @@
+/*
+ * Copyright (C) 2009-2010 Red Hat, Inc. All rights reserved.
+ *
+ * This file is part of LVM2.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU Lesser General Public License v.2.1.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "lib.h"
+#include "metadata.h"
+#include "segtype.h"
+
+/* Add lv as replicator_dev device */
+int replicator_dev_add_rimage(struct replicator_device *rdev,
+			      struct logical_volume *lv)
+{
+	if (!lv || !rdev)
+		return_0;
+
+	if (lv_is_rimage(lv)) {
+		log_error("Logical volume %s is already part of other "
+			  "replicator.", lv->name);
+		return 0;
+	}
+
+	if (rdev->lv) {
+		log_error("Logical volume %s can not be attached to an "
+			  "already defined replicator device", lv->name);
+		return 0;
+	}
+
+	lv_set_hidden(lv);
+	lv->rdevice = rdev;
+	rdev->lv = lv;
+
+	return add_seg_to_segs_using_this_lv(lv, rdev->replicator_dev);
+}
+
+/* Remove lv from replicator_dev device */
+struct logical_volume *replicator_dev_remove_rimage(struct replicator_device *rdev)
+{
+	struct logical_volume *lv;
+
+	if (!rdev || !rdev->lv)
+		return_NULL;
+
+	lv = rdev->lv;
+	if (!remove_seg_from_segs_using_this_lv(lv, rdev->replicator_dev))
+		return_NULL;
+
+	/* FIXME: - check for site references */
+	rdev->lv = NULL;
+	lv->rdevice = NULL;
+	lv_set_visible(lv);
+
+	return lv;
+}
+
+int replicator_dev_add_slog(struct replicator_device *rdev,
+			    struct logical_volume *slog)
+{
+	if (!slog || !rdev)
+		return_0;
+
+	if (rdev->slog) {
+		log_error("Replicator device in site %s already has sync log.",
+			  rdev->rsite->name);
+		return 0;
+	}
+
+	if (slog->rdevice) {
+		log_error("Sync log %s is already used by replicator %s.",
+			  slog->name, slog->rdevice->rsite->replicator->name);
+		return 0;
+	}
+
+	lv_set_hidden(slog);
+	slog->rdevice = rdev;
+	rdev->slog = slog;
+
+	return add_seg_to_segs_using_this_lv(slog, rdev->replicator_dev);
+}
+
+struct logical_volume *replicator_dev_remove_slog(struct replicator_device *rdev)
+{
+	struct logical_volume *lv;
+
+	if (!rdev)
+		return_NULL;
+
+	lv = rdev->slog;
+	if (!lv) {
+		log_error("Replicator device in site %s does not have sync log.",
+			  rdev->rsite->name);
+		return NULL;
+	}
+
+	if (!remove_seg_from_segs_using_this_lv(lv, rdev->replicator_dev))
+		return_NULL;
+
+	rdev->slog = NULL;
+	lv->rdevice = NULL;
+	lv_set_visible(lv);
+
+	return lv;
+}
+
+int replicator_add_replicator_dev(struct logical_volume *replicator_lv,
+				  struct lv_segment *replicator_dev_seg)
+{
+	if (!replicator_lv)
+		return_0;
+
+	if (!(replicator_lv->status & REPLICATOR)) {
+		dm_list_init(&replicator_lv->rsites);
+		lv_set_hidden(replicator_lv);
+		replicator_lv->status |= REPLICATOR;
+	}
+
+	if (!replicator_dev_seg)
+		return 1;
+
+	if (replicator_dev_seg->replicator) {
+		log_error("Replicator device %s is already part of replicator.",
+			  replicator_dev_seg->lv->name);
+		return 0;
+	}
+
+	replicator_dev_seg->replicator = replicator_lv;
+
+	return add_seg_to_segs_using_this_lv(replicator_lv, replicator_dev_seg);
+}
+
+/**
+ * Returns rimage ?? lv upon succeful detach of device
+ * entire LV entry should be removed by this crootall ??
+ */
+struct logical_volume *replicator_remove_replicator_dev(struct lv_segment *replicator_dev_seg)
+{
+	struct logical_volume *lv = NULL;
+
+	log_error("FIXME: not implemented.");
+#if 0
+	/* FIXME: - this is going to be complex.... */
+	if (!replicator_dev_seg)
+		return_NULL;
+
+	/* if slog or rimage - exit */
+
+	if (!remove_seg_from_segs_using_this_lv(lv, replicator_seg))
+		return_NULL;
+
+	replicator_seg->rlog_lv = NULL;
+	lv->status &= ~REPLICATOR_LOG;
+	lv_set_visible(lv);
+#endif
+
+	return lv;
+}
+
+int replicator_add_rlog(struct lv_segment *replicator_seg,
+			struct logical_volume *rlog_lv)
+{
+	if (!rlog_lv)
+		return_0;
+
+	if (rlog_lv->status & REPLICATOR_LOG) {
+		log_error("Rlog device %s is already used.", rlog_lv->name);
+		return 0;
+	}
+
+	lv_set_hidden(rlog_lv);
+	rlog_lv->status |= REPLICATOR_LOG;
+	replicator_seg->rlog_lv = rlog_lv;
+
+	return add_seg_to_segs_using_this_lv(rlog_lv, replicator_seg);
+}
+
+struct logical_volume *replicator_remove_rlog(struct lv_segment *replicator_seg)
+{
+	struct logical_volume *lv;
+
+	if (!replicator_seg)
+		return_0;
+
+	if (!(lv = replicator_seg->rlog_lv)) {
+		log_error("Replog segment %s does not have rlog.",
+			  replicator_seg->lv->name);
+		return NULL;
+	}
+
+	if (!remove_seg_from_segs_using_this_lv(lv, replicator_seg))
+		return_NULL;
+
+	replicator_seg->rlog_lv = NULL;
+	lv->status &= ~REPLICATOR_LOG;
+	lv_set_visible(lv);
+
+	return lv;
+}
+
+
+#if 0
+/*
+ * Create new LV to pretend the original LV
+ * this target will have a 'replicator' segment
+ */
+int lv_add_replicator(struct logical_volume *origin, const char *rep_suffix)
+{
+	struct logical_volume *rep_lv;
+	char *name;
+	size_t slen;
+
+	if (!(name = strstr(origin->name, rep_suffix))) {
+		log_error("Failed to find replicator suffix %s in LV name %s",
+			  rep_suffix, origin->name);
+		return 0;
+	}
+	slen = (size_t)(name - origin->name);
+	name = alloca(slen + 1);
+	memcpy(name, origin->name, slen);
+	name[slen] = 0;
+
+	if ((rep_lv = find_lv(origin->vg, name))) {
+		rep_lv->status |= VIRTUAL;
+		return 1;
+	}
+
+	if (!(rep_lv = lv_create_empty(name, &origin->lvid,
+				       LVM_READ | LVM_WRITE | VISIBLE_LV,
+				       ALLOC_INHERIT, origin->vg)))
+		return_0;
+
+	if (!lv_add_virtual_segment(rep_lv, 0, origin->le_count,
+				    get_segtype_from_string(origin->vg->cmd,
+							    "error")))
+		return_0;
+
+	rep_lv->status |= VIRTUAL;
+	return 1;
+}
+
+int lv_remove_replicator(struct logical_volume *lv)
+{
+	return 1;
+}
+#endif
+
+/**
+ * Is this segment part of active replicator
+ */
+int lv_is_active_replicator_dev(const struct logical_volume *lv)
+{
+	return ((lv->status & REPLICATOR) &&
+		lv->rdevice &&
+		lv->rdevice->rsite &&
+		lv->rdevice->rsite->state == REPLICATOR_STATE_ACTIVE);
+}
+
+/**
+ * Is this LV replicator control device
+ */
+int lv_is_replicator(const struct logical_volume *lv)
+{
+	return ((lv->status & REPLICATOR) &&
+		!dm_list_empty(&lv->segments) &&
+		seg_is_replicator(first_seg(lv)));
+}
+
+/**
+ * Is this LV replicator device
+ */
+int lv_is_replicator_dev(const struct logical_volume *lv)
+{
+	return ((lv->status & REPLICATOR) &&
+		!dm_list_empty(&lv->segments) &&
+		seg_is_replicator_dev(first_seg(lv)));
+}
+
+/**
+ * Is this LV replicated origin lv
+ */
+int lv_is_rimage(const struct logical_volume *lv)
+{
+	return (lv->rdevice && lv->rdevice->lv == lv);
+}
+
+/**
+ * Is this LV rlog
+ */
+int lv_is_rlog(const struct logical_volume *lv)
+{
+	return (lv->status & REPLICATOR_LOG);
+}
+
+/**
+ * Is this LV sync log
+ */
+int lv_is_slog(const struct logical_volume *lv)
+{
+	return (lv->rdevice && lv->rdevice->slog == lv);
+}
+
+/**
+ * Returns first replicator-dev in site in case the LV is replicator-dev,
+ * NULL otherwise
+ */
+struct logical_volume *first_replicator_dev(const struct logical_volume *lv)
+{
+	struct replicator_device *rdev;
+	struct replicator_site *rsite;
+
+	if (lv_is_replicator_dev(lv))
+		dm_list_iterate_items(rsite, &first_seg(lv)->replicator->rsites) {
+			dm_list_iterate_items(rdev, &rsite->rdevices)
+				return rdev->replicator_dev->lv;
+			break;
+		}
+
+	return NULL;
+}
diff --git a/lib/metadata/segtype.h b/lib/metadata/segtype.h
index 7b31c1d..d352928 100644
--- a/lib/metadata/segtype.h
+++ b/lib/metadata/segtype.h
@@ -35,9 +35,13 @@ struct dev_manager;
 #define SEG_VIRTUAL		0x00000020U
 #define SEG_CANNOT_BE_ZEROED	0x00000040U
 #define SEG_MONITORED		0x00000080U
+#define SEG_REPLICATOR		0x00000100U
+#define SEG_REPLICATOR_DEV	0x00000200U
 #define SEG_UNKNOWN		0x80000000U
 
 #define seg_is_mirrored(seg)	((seg)->segtype->flags & SEG_AREAS_MIRRORED ? 1 : 0)
+#define seg_is_replicator(seg)	((seg)->segtype->flags & SEG_REPLICATOR ? 1 : 0)
+#define seg_is_replicator_dev(seg) ((seg)->segtype->flags & SEG_REPLICATOR_DEV ? 1 : 0)
 #define seg_is_striped(seg)	((seg)->segtype->flags & SEG_AREAS_STRIPED ? 1 : 0)
 #define seg_is_snapshot(seg)	((seg)->segtype->flags & SEG_SNAPSHOT ? 1 : 0)
 #define seg_is_virtual(seg)	((seg)->segtype->flags & SEG_VIRTUAL ? 1 : 0)
@@ -110,6 +114,10 @@ struct segment_type *init_error_segtype(struct cmd_context *cmd);
 struct segment_type *init_free_segtype(struct cmd_context *cmd);
 struct segment_type *init_unknown_segtype(struct cmd_context *cmd, const char *name);
 
+#ifdef REPLICATOR_INTERNAL
+int init_replicator_segtype(struct segtype_library *seglib);
+#endif
+
 #ifdef SNAPSHOT_INTERNAL
 struct segment_type *init_snapshot_segtype(struct cmd_context *cmd);
 #endif
diff --git a/lib/replicator/.exported_symbols b/lib/replicator/.exported_symbols
new file mode 100644
index 0000000..1c92c6a
--- /dev/null
+++ b/lib/replicator/.exported_symbols
@@ -0,0 +1 @@
+init_segtype
diff --git a/lib/replicator/Makefile.in b/lib/replicator/Makefile.in
new file mode 100644
index 0000000..ac42730
--- /dev/null
+++ b/lib/replicator/Makefile.in
@@ -0,0 +1,25 @@
+#
+# Copyright (C) 2009-2010 Red Hat, Inc. All rights reserved.
+#
+# This file is part of LVM2.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+top_builddir = @top_builddir@
+
+SOURCES = replicator.c
+
+LIB_SHARED = liblvm2replicator.$(LIB_SUFFIX)
+LIB_VERSION = $(LIB_VERSION_LVM)
+
+include $(top_builddir)/make.tmpl
+
+install: install_lib_shared_plugin
diff --git a/lib/replicator/replicator.c b/lib/replicator/replicator.c
new file mode 100644
index 0000000..6f09321
--- /dev/null
+++ b/lib/replicator/replicator.c
@@ -0,0 +1,790 @@
+/*
+ * Copyright (C) 2009-2010 Red Hat, Inc. All rights reserved.
+ *
+ * This file is part of LVM2.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU Lesser General Public License v.2.1.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "lib.h"
+#include "toolcontext.h"
+#include "metadata.h"
+#include "segtype.h"
+#include "text_export.h"
+#include "text_import.h"
+#include "config.h"
+#include "activate.h"
+#include "str_list.h"
+#ifdef DMEVENTD
+#  include "sharedlib.h"
+#  include "libdevmapper-event.h"
+#endif
+
+/* Dm kernel module name for replicator */
+#define REPLICATOR_MODULE "replicator"
+#define REPLICATOR_DEV_MODULE "replicator-dev"
+
+/*
+ * Macro used as return argument - returns 0.
+ * return is left to be written in the function for better readability.
+ */
+#define SEG_LOG_ERROR(t, p...) \
+	log_error(t " segment %s of logical volume %s.", ## p, \
+		  config_parent_name(sn), seg->lv->name), 0;
+
+
+/*
+ *  Replicator target
+ */
+static const char *_replicator_name(const struct lv_segment *seg)
+{
+	return seg->segtype->name;
+}
+
+/* FIXME: missing implementation */
+static void _replicator_display(const struct lv_segment *seg)
+{
+	//const char *size;
+	//uint32_t s;
+
+	log_print("  Replicator");
+	if (seg->rlog_lv)
+		log_print("  Replicator volume\t%s", seg->rlog_lv->name);
+}
+
+/* Wrapper for get_config_uint32() with default value */
+static uint32_t _get_config_uint32(const struct config_node *cn,
+				   const char *path,
+				   uint32_t def)
+{
+	uint32_t t;
+
+	return get_config_uint32(cn, path, &t) ? t : def;
+}
+
+/* Wrapper for get_config_uint64() with default value */
+static uint64_t _get_config_uint64(const struct config_node *cn,
+				   const char *path,
+				   uint64_t def)
+{
+	uint64_t t;
+
+	return get_config_uint64(cn, path, &t) ? t : def;
+}
+
+
+/* Strings replicator_state_t enum */
+static const char _state_txt[NUM_REPLICATOR_STATE][8] = {
+	"passive",
+	"active"
+};
+
+/* Parse state string */
+static replicator_state_t _get_state(const struct config_node *sn,
+				     const char *path, replicator_state_t def)
+{
+	char *str;
+	unsigned i;
+
+	if (get_config_str(sn, path, &str)) {
+		for (i = 0; i < sizeof(_state_txt)/sizeof(_state_txt[0]); ++i)
+			if (strcasecmp(str, _state_txt[i]) == 0)
+				return (replicator_state_t) i;
+
+		log_warn("%s: unknown value '%s', using default '%s' state",
+			 path, str, _state_txt[def]);
+	}
+
+	return def;
+}
+
+/* Strings for replicator_action_t enum */
+static const char _op_mode_txt[NUM_DM_REPLICATOR_MODES][8] = {
+	"sync",
+	"warn",
+	"stall",
+	"drop",
+	"fail"
+};
+
+
+/* Parse action string */
+static dm_replicator_mode_t _get_op_mode(const struct config_node *sn,
+					 const char *path, dm_replicator_mode_t def)
+{
+	char *str;
+	unsigned i;
+
+	if (get_config_str(sn, path, &str)) {
+		for (i = 0; i < sizeof(_op_mode_txt)/sizeof(_op_mode_txt[0]); ++i)
+			if (strcasecmp(str, _op_mode_txt[i]) == 0) {
+				log_very_verbose("Setting %s to %s",
+						 path, _op_mode_txt[i]);
+				return (dm_replicator_mode_t) i;
+			}
+		log_warn("%s: unknown value '%s', using default '%s' operation mode",
+			 path, str, _op_mode_txt[def]);
+	}
+
+	return def;
+}
+
+static struct replicator_site *_get_site(struct logical_volume *replicator,
+					 const char *key)
+{
+	struct dm_pool *mem = replicator->vg->vgmem;
+	struct replicator_site *rsite;
+
+	dm_list_iterate_items(rsite, &replicator->rsites)
+		if (strcasecmp(rsite->name, key) == 0)
+			return rsite;
+
+	if (!(rsite = dm_pool_zalloc(mem, sizeof(*rsite))))
+		return_NULL;
+
+	if (!(rsite->name = dm_pool_strdup(mem, key)))
+		return_NULL;
+
+	rsite->replicator = replicator;
+	dm_list_init(&rsite->rdevices);
+	dm_list_add(&replicator->rsites, &rsite->list);
+
+	return rsite;
+}
+
+
+/* Parse replicator site element */
+static int _add_site(struct lv_segment *seg,
+		     const char *key,
+		     const struct config_node *sn)
+{
+	struct dm_pool *mem = seg->lv->vg->vgmem;
+	const struct config_node *cn;
+	struct replicator_site *rsite;
+
+	if (!(rsite = _get_site(seg->lv, key)))
+		return_0;
+
+	if (!find_config_node(sn, "site_index"))
+		return SEG_LOG_ERROR("Mandatory site_index is missing for");
+
+	rsite->state = _get_state(sn, "state", REPLICATOR_STATE_PASSIVE);
+	rsite->site_index = _get_config_uint32(sn, "site_index", 0);
+	if (rsite->site_index > seg->rsite_index_highest)
+		return SEG_LOG_ERROR("site_index=%d > highest_site_index=%d for",
+				     rsite->site_index, seg->rsite_index_highest);
+
+	rsite->fall_behind_data = _get_config_uint64(sn, "fall_behind_data", 0);
+	rsite->fall_behind_ios = _get_config_uint32(sn, "fall_behind_ios", 0);
+	rsite->fall_behind_timeout = _get_config_uint32(sn, "fall_behind_timeout", 0);
+	rsite->op_mode = DM_REPLICATOR_SYNC;
+
+	if (rsite->fall_behind_data ||
+	    rsite->fall_behind_ios ||
+	    rsite->fall_behind_timeout) {
+		if (rsite->fall_behind_data && rsite->fall_behind_ios)
+			return SEG_LOG_ERROR("Defined both fall_behind_data "
+					     "and fall_behind_ios in");
+
+		if (rsite->fall_behind_data && rsite->fall_behind_timeout)
+			return SEG_LOG_ERROR("Defined both fall_behind_data "
+					     "and fall_behind_timeout in");
+
+		if (rsite->fall_behind_ios && rsite->fall_behind_timeout)
+			return SEG_LOG_ERROR("Defined both fall_behind_ios "
+					     "and fall_behind_timeout in");
+
+		rsite->op_mode = _get_op_mode(sn, "operation_mode",
+					      rsite->op_mode);
+	}
+
+	if ((cn = find_config_node(sn, "volume_group"))) {
+		if (!cn->v || cn->v->type != CFG_STRING)
+			return SEG_LOG_ERROR("volume_group must be a string in");
+
+		if (!(rsite->vg_name = dm_pool_strdup(mem, cn->v->v.str)))
+			return_0;
+
+	} else if (rsite->site_index != 0)
+		return SEG_LOG_ERROR("volume_group is mandatory for remote site in");
+
+	return 1;
+}
+
+
+/* Import replicator segment */
+static int _replicator_text_import(struct lv_segment *seg,
+				   const struct config_node *sn,
+				   struct dm_hash_table *pv_hash __attribute((unused)))
+{
+	const struct config_node *cn;
+	struct logical_volume *rlog_lv;
+
+	if (!replicator_add_replicator_dev(seg->lv, NULL))
+		return_0;
+
+	if (!(cn = find_config_node(sn, "replicator_log")) ||
+	    !cn->v || cn->v->type != CFG_STRING)
+		return SEG_LOG_ERROR("Replicator log type must be a string in");
+
+	if (!(rlog_lv = find_lv(seg->lv->vg, cn->v->v.str)))
+		return SEG_LOG_ERROR("Unknown replicator log %s in",
+				     cn->v->v.str);
+
+	if (!(cn = find_config_node(sn, "replicator_log_type")) ||
+	    !cn->v || cn->v->type != CFG_STRING)
+		return SEG_LOG_ERROR("Replicator log's type must be a string in");
+	if (strcasecmp(cn->v->v.str, "ringbuffer"))
+		return SEG_LOG_ERROR("Only ringbuffer replicator log type is supported in");
+
+	if (!(seg->rlog_type = dm_pool_strdup(seg->lv->vg->vgmem, cn->v->v.str)))
+		return_0;
+
+
+	log_very_verbose("replicator_log = %s", rlog_lv->name);
+	log_very_verbose("replicator_log_type = %s", seg->rlog_type);
+
+	if (!replicator_add_rlog(seg, rlog_lv))
+		return_0;
+
+	seg->rdevice_index_highest = _get_config_uint64(sn, "highest_device_index", 0);
+	seg->rsite_index_highest = _get_config_uint32(sn, "highest_site_index", 0);
+
+	seg->region_size = _get_config_uint32(sn, "sync_log_size", 0);
+
+	for (; sn; sn = sn->sib)
+		if (!sn->v) {
+			for (cn = sn->sib; cn; cn = cn->sib)
+				if (!cn->v && (strcasecmp(cn->key ,sn->key) == 0))
+					return SEG_LOG_ERROR("Detected duplicate site "
+							     "name %s in", sn->key);
+			if (!_add_site(seg, sn->key, sn->child))
+				return_0;
+		}
+	return 1;
+}
+
+/* Export replicator segment */
+static int _replicator_text_export(const struct lv_segment *seg,
+				   struct formatter *f)
+{
+	struct replicator_site *rsite;
+
+	if (!seg->rlog_lv)
+                return_0;
+
+	outf(f, "replicator_log = \"%s\"", seg->rlog_lv->name);
+	outf(f, "replicator_log_type = \"%s\"", seg->rlog_type);
+	outf(f, "highest_device_index = %" PRIu64, seg->rdevice_index_highest);
+	outf(f, "highest_site_index = %d", seg->rsite_index_highest);
+
+	if (seg->region_size)
+		outsize(f, (uint64_t)seg->region_size,
+			"sync_log_size = %" PRIu32, seg->region_size);
+
+	if (!dm_list_empty(&seg->lv->rsites))
+		outnl(f);
+
+	dm_list_iterate_items(rsite, &seg->lv->rsites) {
+		outf(f, "%s {", rsite->name);
+		out_inc_indent(f);
+
+		outf(f, "state = \"%s\"", _state_txt[rsite->state]);
+		outf(f, "site_index = %d", rsite->site_index);
+
+		/* Only non-default parameters are written */
+		if (rsite->op_mode != DM_REPLICATOR_SYNC)
+			outf(f, "operation_mode = \"%s\"",
+			     _op_mode_txt[rsite->op_mode]);
+		if (rsite->fall_behind_timeout)
+			outfc(f, "# seconds", "fall_behind_timeout = %u",
+			     rsite->fall_behind_timeout);
+		if (rsite->fall_behind_ios)
+			outfc(f, "# io operations", "fall_behind_ios = %u",
+			     rsite->fall_behind_ios);
+		if (rsite->fall_behind_data)
+			outsize(f, rsite->fall_behind_data, "fall_behind_data = %" PRIu64,
+				rsite->fall_behind_data);
+		if (rsite->state != REPLICATOR_STATE_ACTIVE && rsite->vg_name)
+			outf(f, "volume_group = \"%s\"", rsite->vg_name);
+
+		out_dec_indent(f);
+		outf(f, "}");
+	}
+
+	return 1;
+}
+
+#ifdef DEVMAPPER_SUPPORT
+static int _replicator_add_target_line(struct dev_manager *dm,
+				       struct dm_pool *mem,
+				       struct cmd_context *cmd,
+				       void **target_state,
+				       struct lv_segment *seg,
+				       struct dm_tree_node *node,
+				       uint64_t len,
+				       uint32_t *pvmove_mirror_count)
+{
+	const char *rlog_dlid;
+	struct replicator_site *rsite;
+
+	if (!seg->rlog_lv)
+		return_0;
+
+	if (!(rlog_dlid = build_dm_uuid(mem, seg->rlog_lv->lvid.s, NULL)))
+		return_0;
+
+	dm_list_iterate_items(rsite, &seg->lv->rsites) {
+		if (!dm_tree_node_add_replicator_target(node,
+							seg->rlog_lv->size,
+							rlog_dlid,
+							seg->rlog_type,
+							rsite->site_index,
+							rsite->op_mode,
+							rsite->fall_behind_timeout,
+							rsite->fall_behind_data,
+							rsite->fall_behind_ios)) {
+			if (rsite->site_index == 0) {
+				log_error("Failed to add replicator log '%s' "
+					  "to replicator '%s'.",
+					  rlog_dlid, seg->lv->name);
+				return 0;
+			}
+			// FIXME:
+		}
+	}
+
+	return 1;
+}
+
+/* FIXME: write something useful for replicator here */
+static int _replicator_target_percent(void **target_state,
+				      percent_range_t *percent_range,
+				      struct dm_pool *mem,
+				      struct cmd_context *cmd,
+				      struct lv_segment *seg,
+				      char *params, uint64_t *total_numerator,
+				      uint64_t *total_denominator)
+{
+	return 1;
+}
+
+/* Check for module presence */
+static int _replicator_target_present(struct cmd_context *cmd,
+				      const struct lv_segment *seg __attribute((unused)),
+				      unsigned *attributes __attribute((unused)))
+{
+	static int _checked = 0;
+	static int _present = 0;
+
+	if (!_checked) {
+		_present = target_present(cmd, REPLICATOR_MODULE, 1);
+		_checked = 1;
+	}
+
+	return _present;
+}
+
+#endif
+
+static int _replicator_modules_needed(struct dm_pool *mem,
+				      const struct lv_segment *seg __attribute((unused)),
+				      struct dm_list *modules)
+{
+	if (!str_list_add(mem, modules, REPLICATOR_MODULE))
+		return_0;
+
+	if (!str_list_add(mem, modules, REPLICATOR_DEV_MODULE))
+		return_0;
+
+	return 1;
+}
+
+static void _replicator_destroy(const struct segment_type *segtype)
+{
+	dm_free((void *)segtype);
+}
+
+static struct segtype_handler _replicator_ops = {
+	.name = _replicator_name,
+	.display = _replicator_display,
+	.text_import = _replicator_text_import,
+	.text_export = _replicator_text_export,
+#ifdef DEVMAPPER_SUPPORT
+	.add_target_line = _replicator_add_target_line,
+	.target_percent = _replicator_target_percent,
+	.target_present = _replicator_target_present,
+#endif
+	.modules_needed = _replicator_modules_needed,
+	.destroy = _replicator_destroy,
+};
+
+/*
+ *  Replicator-dev  target
+ */
+static void _replicator_dev_display(const struct lv_segment *seg)
+{
+	//const char *size;
+	//uint32_t s;
+	// FIXME: debug test code for now
+	log_print("  Replicator\t\t%u", seg->area_count);
+	log_print("  Mirror size\t\t%u", seg->area_len);
+	if (seg->log_lv)
+		log_print("  Replicator log volume\t%s", seg->rlog_lv->name);
+
+}
+
+static int _add_device(struct lv_segment *seg,
+		       const char *site_name,
+		       const struct config_node *sn,
+		       uint64_t devidx)
+{
+	struct dm_pool *mem = seg->lv->vg->vgmem;
+	struct logical_volume *lv = NULL;
+	struct logical_volume *slog_lv = NULL;
+	struct replicator_site *rsite = _get_site(seg->replicator, site_name);
+	struct replicator_device *rdev;
+	const char *dev_str = NULL;
+	const char *slog_str = NULL;
+	const struct config_node *cn;
+
+	dm_list_iterate_items(rdev, &rsite->rdevices)
+		if (rdev->replicator_dev == seg)
+			return SEG_LOG_ERROR("Duplicate site found in");
+
+	if ((cn = find_config_node(sn, "sync_log"))) {
+		if (!cn->v || !cn->v->v.str)
+			return SEG_LOG_ERROR("Sync log must be a string in");
+		slog_str = cn->v->v.str;
+	}
+
+	if (!(cn = find_config_node(sn, "logical_volume")) ||
+	    !cn->v || !cn->v->v.str)
+		return SEG_LOG_ERROR("Logical volume must be a string in");
+
+	dev_str = cn->v->v.str;
+
+	if (!seg->lv->rdevice) {
+		if (slog_str)
+			return SEG_LOG_ERROR("Sync log %s defined for local "
+					     "device in", slog_str);
+
+		/* Check for device in current VG */
+		if (!(lv = find_lv(seg->lv->vg, dev_str)))
+			return SEG_LOG_ERROR("Logical volume %s not found in",
+					     dev_str);
+	} else {
+		if (!slog_str)
+			return SEG_LOG_ERROR("Sync log is missing for remote "
+					     "device in");
+		/* Check for slog device in current VG */
+		if (!(slog_lv = find_lv(seg->lv->vg, slog_str)))
+			return SEG_LOG_ERROR("Sync log %s not found in",
+					     slog_str);
+	}
+
+	if (!(rdev = dm_pool_zalloc(mem, sizeof(*rdev))))
+		return_0;
+
+	if (!(rdev->name = dm_pool_strdup(mem, dev_str)))
+		return_0;
+
+	rdev->replicator_dev = seg;
+	rdev->rsite = rsite;
+	rdev->device_index = devidx;
+
+	if (!seg->lv->rdevice) {
+		if (!replicator_dev_add_rimage(rdev, lv))
+			return SEG_LOG_ERROR("LV inconsistency found in");
+		seg->lv->rdevice = rdev;
+	} else {
+		if (!slog_str ||
+		    !(rdev->slog_name = dm_pool_strdup(mem, slog_str)))
+			return_0;
+
+		if (!replicator_dev_add_slog(rdev, slog_lv))
+			return SEG_LOG_ERROR("Sync log inconsistency found in");
+	}
+
+	dm_list_add(&rsite->rdevices, &rdev->list);// linked site list
+
+	return 1;
+}
+
+/* Import replicator segment */
+static int _replicator_dev_text_import(struct lv_segment *seg,
+				       const struct config_node *sn,
+				       struct dm_hash_table *pv_hash __attribute((unused)))
+{
+	const struct config_node *cn;
+	struct logical_volume *replicator;
+	uint64_t devidx;
+
+	if (!(cn = find_config_node(sn, "replicator")))
+		return SEG_LOG_ERROR("Replicator is missing for");
+
+	if (!cn->v || !cn->v->v.str)
+		return SEG_LOG_ERROR("Replicator must be a string for");
+
+	if (!(replicator = find_lv(seg->lv->vg, cn->v->v.str)))
+		return SEG_LOG_ERROR("Unknown replicator %s for", cn->v->v.str);
+
+	if (!replicator_add_replicator_dev(replicator, seg))
+		return_0;
+
+	log_very_verbose("replicator=%s", replicator->name);
+
+	/* Mandatory */
+	if (!find_config_node(sn, "device_index") ||
+	    !get_config_uint64(sn, "device_index", &devidx))
+		return SEG_LOG_ERROR("Could not read 'device_index' for");
+
+	/* Read devices from sites */
+	for (; sn; sn = sn->sib)
+		if (!(sn->v) && !_add_device(seg, sn->key, sn->child, devidx))
+			return_0;
+
+	if (!seg->lv->rdevice)
+		return SEG_LOG_ERROR("Replicator device without site in");
+
+	seg->rlog_lv = NULL;
+	seg->lv->status |= REPLICATOR;
+
+	return 1;
+}
+
+/* Export replicator-dev segment */
+static int _replicator_dev_text_export(const struct lv_segment *seg,
+				       struct formatter *f)
+{
+	struct replicator_site *rsite;
+	struct replicator_device *rdev;
+
+	if (!seg->replicator || !seg->lv->rdevice)
+		return_0;
+
+	outf(f, "replicator = \"%s\"", seg->replicator->name);
+	outf(f, "device_index = %" PRId64, seg->lv->rdevice->device_index);
+
+	outnl(f);
+
+	dm_list_iterate_items(rsite, &seg->replicator->rsites) {
+		dm_list_iterate_items(rdev, &rsite->rdevices) {
+			if (rdev->replicator_dev != seg)
+				continue;
+
+			outf(f, "%s {", rdev->rsite->name);
+
+			out_inc_indent(f);
+
+			outf(f, "logical_volume = \"%s\"",
+			     rdev->name ? rdev->name : rdev->lv->name);
+
+			if (rdev->slog)
+				outf(f, "sync_log = \"%s\"", rdev->slog->name);
+			else if (rdev->slog_name)
+				outf(f, "sync_log = \"%s\"", rdev->slog_name);
+
+			out_dec_indent(f);
+
+			outf(f, "}");
+		}
+	}
+
+	return 1;
+}
+
+#ifdef DEVMAPPER_SUPPORT
+/*
+ * Add target for passive site matching the device index
+ */
+static int _replicator_dev_add_target_line(struct dev_manager *dm,
+					   struct dm_pool *mem,
+					   struct cmd_context *cmd,
+					   void **target_state,
+					   struct lv_segment *seg,
+					   struct dm_tree_node *node,
+					   uint64_t len,
+					   uint32_t *pvmove_mirror_count)
+{
+	const char *replicator_dlid, *rdev_dlid, *slog_dlid;
+	struct replicator_device *rdev, *rdev_search;
+	struct replicator_site *rsite;
+	uint32_t slog_size;
+	uint32_t slog_flags;
+
+	if (!lv_is_active_replicator_dev(seg->lv)) {
+		/* Create passive linear mapping */
+		log_very_verbose("Inactive replicator %s using %s.",
+				 seg->lv->name, seg->lv->rdevice->lv->name);
+		if (!dm_tree_node_add_linear_target(node, seg->lv->size))
+			return_0;
+		if (!(rdev_dlid = build_dm_uuid(mem, seg->lv->rdevice->lv->lvid.s, NULL)))
+			return_0;
+		return dm_tree_node_add_target_area(node, NULL, rdev_dlid, 0);
+	} else if (seg->lv->rdevice->rsite->site_index) {
+		log_error("Active site with site_index != 0 (%s, %d)",
+			  seg->lv->rdevice->rsite->name,
+			  seg->lv->rdevice->rsite->site_index);
+		return 0; /* Replicator without any active site */
+	}
+
+	/*
+	 * At this point all devices that have some connection with replicator
+	 * must be present in dm_tree
+	 */
+	if (!seg_is_replicator_dev(seg) ||
+	    !(replicator_dlid = build_dm_uuid(mem, seg->replicator->lvid.s, NULL)))
+		return_0;
+
+	/* Select remote devices with the same device index */
+	dm_list_iterate_items(rsite, &seg->replicator->rsites) {
+		if (rsite->site_index == 0) {
+			/* Local slink0 device */
+			rdev = seg->lv->rdevice;
+		} else {
+			rdev = NULL;
+			dm_list_iterate_items(rdev_search, &rsite->rdevices) {
+				if (rdev_search->replicator_dev == seg) {
+					rdev = rdev_search;
+					break;
+				}
+			}
+
+			if (!rdev) {
+				log_error(INTERNAL_ERROR "rdev list not found.");
+				return 0;
+			}
+		}
+
+		if (!rdev->lv ||
+		    !(rdev_dlid = build_dm_uuid(mem, rdev->lv->lvid.s, NULL)))
+			return_0;
+
+		slog_dlid = NULL;
+
+		/* Using either disk or core (in memory) log */
+		if (rdev->slog) {
+			slog_flags = DM_NOSYNC;
+			slog_size = (uint32_t) rdev->slog->size;
+			if (!(slog_dlid = build_dm_uuid(mem, rdev->slog->lvid.s, NULL)))
+				return_0;
+		} else if (rdev->slog_name &&
+			   sscanf(rdev->slog_name, "%" PRIu32, &slog_size) == 1) {
+			slog_flags = DM_CORELOG | DM_FORCESYNC;
+			if (slog_size == 0) {
+				log_error("Failed to use empty corelog size "
+					  "in replicator '%s'.",
+					  rsite->replicator->name);
+				return 0;
+			}
+		} else  {
+			slog_flags = DM_CORELOG | DM_FORCESYNC;
+			slog_size = 0; /* NOLOG */
+		}
+
+		if (!dm_tree_node_add_replicator_dev_target(node,
+							    seg->lv->size,
+							    replicator_dlid,
+							    seg->lv->rdevice->device_index,
+							    rdev_dlid,
+							    rsite->site_index,
+							    slog_dlid,
+							    slog_flags,
+							    slog_size)) {
+			return_0;
+			/* FIXME: handle 'state = dropped' in future */
+		}
+	}
+
+	return 1;
+}
+
+/* FIXME: write something useful for replicator-dev here */
+static int _replicator_dev_target_percent(void **target_state,
+					  percent_range_t *percent_range,
+					  struct dm_pool *mem,
+					  struct cmd_context *cmd,
+					  struct lv_segment *seg,
+					  char *params,
+					  uint64_t *total_numerator,
+					  uint64_t *total_denominator)
+{
+	return 1;
+}
+
+/* Check for module presence */
+static int _replicator_dev_target_present(struct cmd_context *cmd,
+					  const struct lv_segment *seg __attribute((unused)),
+					  unsigned *attributes __attribute((unused)))
+{
+	static int _checked = 0;
+	static int _present = 0;
+
+	if (!_checked) {
+		_present = target_present(cmd, REPLICATOR_DEV_MODULE, 1);
+		_checked = 1;
+	}
+
+	return _present;
+}
+
+#endif
+
+static struct segtype_handler _replicator_dev_ops = {
+	.name = _replicator_name,
+	.display = _replicator_dev_display,
+	.text_import = _replicator_dev_text_import,
+	.text_export = _replicator_dev_text_export,
+#ifdef DEVMAPPER_SUPPORT
+	.add_target_line = _replicator_dev_add_target_line,
+	.target_percent = _replicator_dev_target_percent,
+	.target_present = _replicator_dev_target_present,
+#endif
+	.modules_needed = _replicator_modules_needed,
+	.destroy = _replicator_destroy,
+};
+
+#ifdef REPLICATOR_INTERNAL
+int init_replicator_segtype(struct segtype_library *seglib)
+#else /* Shared */
+int init_multiple_segtype(struct segtype_library *seglib);
+int init_multiple_segtype(struct segtype_library *seglib)
+#endif
+{
+	struct segment_type *segtype;
+
+	if (!(segtype = dm_malloc(sizeof(*segtype))))
+		return_0;
+
+	segtype->ops = &_replicator_ops;
+	segtype->name = REPLICATOR_MODULE;
+	segtype->private = NULL;
+	segtype->flags = SEG_REPLICATOR;
+
+	if (!lvm_register_segtype(seglib, segtype))
+		return_0;
+
+	log_very_verbose("Initialised segtype: " REPLICATOR_MODULE);
+
+	if (!(segtype = dm_malloc(sizeof(*segtype))))
+		return_0;
+
+	segtype->ops = &_replicator_dev_ops;
+	segtype->name = REPLICATOR_DEV_MODULE;
+	segtype->private = NULL;
+	segtype->flags = SEG_REPLICATOR_DEV;
+
+	if (!lvm_register_segtype(seglib, segtype))
+		return_0;
+
+	log_very_verbose("Initialised segtype: " REPLICATOR_DEV_MODULE);
+
+	return 1;
+}
-- 
1.7.0.1


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]