[lvm-devel] [PATCH 03/13] Replicator: add lvm support

Zdenek Kabelac zkabelac at redhat.com
Mon Oct 5 14:00:30 UTC 2009


Adding basic lib lvm elements for Replicator
Validation of Replicator segment

Signed-off-by: Zdenek Kabelac <zkabelac at redhat.com>
---
 configure.in                     |   17 +
 lib/Makefile.in                  |    9 +
 lib/commands/toolcontext.c       |    5 +
 lib/metadata/lv_manip.c          |    1 +
 lib/metadata/merge.c             |   14 +
 lib/metadata/metadata-exported.h |   94 ++++-
 lib/metadata/replicator.c        |  339 ++++++++++++++
 lib/metadata/segtype.h           |    8 +
 lib/replicator/.exported_symbols |    1 +
 lib/replicator/Makefile.in       |   28 ++
 lib/replicator/replicator.c      |  912 ++++++++++++++++++++++++++++++++++++++
 11 files changed, 1427 insertions(+), 1 deletions(-)
 create mode 100644 lib/metadata/replicator.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 bf360ed..197e17a 100644
--- a/configure.in
+++ b/configure.in
@@ -308,6 +308,21 @@ if test x$MIRRORS = xinternal; then
 fi
 
 ################################################################################
+dnl -- Asynchronous Volume Replicator inclusion type
+AC_MSG_CHECKING(whether to include replicator)
+AC_ARG_WITH(replicator, AC_HELP_STRING([--with-replicator=TYPE],
+        [Replicator support: internal/shared/none [[TYPE=none]]]),
+        [ REPLICATOR="$withval" ], [ REPLICATOR="none" ])
+AC_MSG_RESULT($REPLICATOR)
+
+case "$REPLICATOR" in
+ none|shared) ;;
+ internal) AC_DEFINE([REPLICATOR_INTERNAL], 1,
+                     [Define to 1 to include built-in support for replicator.]) ;;
+ *) AC_MSG_ERROR([--with-replicator parameter invalid ($REPLICATOR)]) ;;
+esac
+
+################################################################################
 dnl -- Disable readline
 AC_MSG_CHECKING(whether to enable readline)
 AC_ARG_ENABLE([readline],
@@ -1116,6 +1131,7 @@ AC_SUBST(LVM_PATCHLEVEL)
 AC_SUBST(LVM_RELEASE)
 AC_SUBST(LVM_RELEASE_DATE)
 AC_SUBST(MIRRORS)
+AC_SUBST(REPLICATOR)
 AC_SUBST(MSGFMT)
 AC_SUBST(OWNER)
 AC_SUBST(PKGCONFIG)
@@ -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 9396fb2..38a3589 100644
--- a/lib/Makefile.in
+++ b/lib/Makefile.in
@@ -33,6 +33,10 @@ ifeq ("@MIRRORS@", "shared")
   SUBDIRS += mirror
 endif
 
+ifeq ("@REPLICATOR@", "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.c \
 	metadata/segtype.c \
 	metadata/snapshot_manip.c \
 	misc/crc.c \
@@ -125,6 +130,10 @@ ifeq ("@MIRRORS@", "internal")
   SOURCES += mirror/mirrored.c
 endif
 
+ifeq ("@REPLICATOR@", "internal")
+  SOURCES += replicator/replicator.c
+endif
+
 ifeq ("@DEVMAPPER@", "yes")
   SOURCES +=\
 	activate/dev_manager.c \
diff --git a/lib/commands/toolcontext.c b/lib/commands/toolcontext.c
index 2a56100..d1f4724 100644
--- a/lib/commands/toolcontext.c
+++ b/lib/commands/toolcontext.c
@@ -904,6 +904,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/metadata/lv_manip.c b/lib/metadata/lv_manip.c
index 7bcd64f..51e100e 100644
--- a/lib/metadata/lv_manip.c
+++ b/lib/metadata/lv_manip.c
@@ -1876,6 +1876,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 66e9ce0..3233d2b 100644
--- a/lib/metadata/merge.c
+++ b/lib/metadata/merge.c
@@ -66,6 +66,8 @@ int check_lv_segments(struct logical_volume *lv, int complete_vg)
 	int r = 1;
 	uint32_t area_multiplier, s;
 	struct seg_list *sl;
+	struct replicator_site *rsite;
+	struct replicator_device *rdev;
 
 	dm_list_iterate_items(seg, &lv->segments) {
 		seg_count++;
@@ -207,6 +209,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 bf830aa..2d08c2d 100644
--- a/lib/metadata/metadata-exported.h
+++ b/lib/metadata/metadata-exported.h
@@ -61,6 +61,9 @@
 //#define PRECOMMITTED		0x00200000U	/* VG - internal use only */
 #define CONVERTING		0x00400000U	/* LV */
 
+#define REPLICATOR		0x10000000U	/* LV -internal use only for replicator/replicator-dev */
+#define REPLICATOR_LOG		0x20000000U	/* LV -internal use only for replicator/replicator-dev */
+
 #define MISSING_PV              0x00800000U	/* PV */
 #define PARTIAL_LV              0x01000000U	/* LV - derived flag, not
 						   written out in metadata*/
@@ -277,6 +280,54 @@ struct lv_segment_area {
 };
 
 struct segment_type;
+
+/* ++ replicator datatypes */
+typedef enum {
+	REPLICATOR_ACTION_WARN,
+	REPLICATOR_ACTION_STALL,
+	REPLICATOR_ACTION_DROP,
+	REPLICATOR_ACTION_FAIL,
+	NUM_REPLICATOR_ACTION
+} replicator_action_t;
+
+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;
+	const char *vg_name;		/* vg name/uuid */
+	struct volume_group *vg;	/* site's volume group */
+	unsigned site_index;
+	replicator_state_t state;	/* active|pasive state of site */
+	replicator_action_t async_action;/* fail|warn|drop|resync|stall */
+	uint64_t fall_behind_data;	/* in 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;		/* any device path/uuid */
+	struct logical_volume *lv;	/* lv from rsite's VG */
+	struct logical_volume *slog;	/* llog lv from VG  */
+	const char *slog_name;		/* ?debug? - specify ram based core log size */
+};
+
+/* -- replicator datatypes */
+
 struct lv_segment {
 	struct dm_list list;
 	struct logical_volume *lv;
@@ -295,13 +346,19 @@ struct lv_segment {
 	struct logical_volume *cow;
 	struct dm_list origin_list;
 	uint32_t chunk_size;	/* For snapshots - in sectors */
-	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 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
@@ -327,6 +384,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;
@@ -520,6 +580,7 @@ uint64_t extents_from_size(struct cmd_context *cmd, uint64_t size,
 struct lvcreate_params {
 	/* flags */
 	int snapshot; /* snap */
+	int replicator; /* replicator */
 	int zero; /* all */
 	int major; /* all */
 	int minor; /* all */
@@ -682,6 +743,37 @@ 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.c */
+
+int lvm_replicator_add_dev(struct logical_volume *replicator_lv, struct lv_segment *replicator_dev_seg);
+/*
+ * returns rimage ?? lv upon succeful detach of device
+ * entire LV entry should be removed by this crootall ??
+ */
+struct logical_volume *lvm_replicator_remove_dev(struct lv_segment *replicator_dev_seg);//MAYBE: struct replicator_device *rdev??
+int lvm_replicator_add_rlog(struct lv_segment *replicator_seg, struct logical_volume *rlog_lv);
+struct logical_volume *lvm_replicator_remove_rlog(struct lv_segment *replicator_seg);
+
+int lvm_replicator_dev_add_slog(struct replicator_device *rdev, struct logical_volume *llog_lv);
+struct logical_volume *lvm_replicator_dev_remove_slog(struct replicator_device *rdev);
+int lvm_replicator_dev_add_rimage(struct replicator_device *rdev, struct logical_volume *lv);
+struct logical_volume *lvm_replicator_dev_remove_rimage(struct replicator_device *rdev);
+
+/* is this segment part of active replicator */
+int lv_is_active_replicator_dev(const struct logical_volume *lv);
+
+/* is this lv replicator control device */
+int lv_is_replicator(const struct logical_volume *lv);
+/* is this lv replicator device */
+int lv_is_replicator_dev(const struct logical_volume *lv);
+/* is this lv replicated origin lv */
+int lv_is_rimage(const struct logical_volume *lv);
+/* is this lv rlog */
+int lv_is_rlog(const struct logical_volume *lv);
+/* is this lv sync log */
+int lv_is_slog(const struct logical_volume *lv);
+/* --  metadata/replicator.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.c b/lib/metadata/replicator.c
new file mode 100644
index 0000000..ca87085
--- /dev/null
+++ b/lib/metadata/replicator.c
@@ -0,0 +1,339 @@
+/*
+ * Copyright (C) 2009 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 "toolcontext.h"
+#include "segtype.h"
+#include "archiver.h"
+#include "lvm-string.h"
+#include "str_list.h"
+#include "defaults.h"
+#include "lv_alloc.h"
+
+/* Add lv as replicator device */
+int lvm_replicator_dev_add_rimage(struct replicator_device *rdev,
+				  struct logical_volume *lv)
+{
+	if (!lv || !rdev)
+		return_0;
+	log_verbose("try add_rimage");
+
+	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;
+
+	//{ static int  kill = 4; if (getenv("LVMKILL") && kill-- < 0) abort(); }
+
+	log_verbose("LV rdev rd:%p repseg:%p", rdev, rdev->replicator_dev);
+	return add_seg_to_segs_using_this_lv(lv, rdev->replicator_dev);
+}
+
+/* Remove lv from replicator device */
+struct logical_volume *lvm_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 lvm_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 part of other replicator.",
+			  slog->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 *lvm_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 lvm_replicator_add_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);
+}
+
+struct logical_volume *lvm_replicator_remove_dev(struct lv_segment *replicator_dev_seg)
+{
+	struct logical_volume *lv = NULL;
+
+#if 0
+	// FIXME - this is going to be complex....
+	if (!replicator_dev_seg)
+		return_NULL;
+
+	// if slog -  exit
+	// if 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 lvm_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 *lvm_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 lvm_replicator_lv_add(struct logical_volume *origin, const char *rep_suffix)
+{
+	struct logical_volume *rep_lv;
+	//struct lv_segment *seg;
+	char *name;
+	size_t slen;
+
+	//name = strcpy(alloc(strlen(s) + 1), s), if (!strstr(name, suffix) ? ),
+
+	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;
+		log_very_verbose("Found already created lv  %s	le:%" PRIu32,
+				 rep_lv->name, rep_lv->le_count);
+		return 1;
+	}
+
+	if (!(rep_lv = lv_create_empty(name, &origin->lvid,
+				       LVM_READ | LVM_WRITE | VISIBLE_LV,
+				       ALLOC_INHERIT, origin->vg)))
+		return_0;
+
+	log_very_verbose("Created empty lv  %s	 %s le:%" PRIu32,
+			 rep_lv->name, origin->name, origin->le_count);
+
+	if (!lv_add_virtual_segment(rep_lv, 0, origin->le_count,
+				    get_segtype_from_string(origin->vg->cmd,
+							    "error")))
+		return_0;
+
+	/*
+	if (!(seg = alloc_snapshot_seg(rep, 0, 0)))
+		return_0;
+
+	seg->chunk_size = chunk_size;
+	seg->origin = origin;
+	seg->cow = cow;
+	seg->lv->status |= SNAPSHOT;
+
+	origin->origin_count++;
+	origin->vg->snapshot_count++;
+	origin->vg->lv_count--;
+	cow->snapshot = seg;
+
+	cow->status &= ~VISIBLE_LV;
+
+	dm_list_add(&origin->snapshot_segs, &seg->origin_list);
+	*/
+
+	//rep_lv->status |= REPLICATOR | VIRTUAL;
+	rep_lv->status |= VIRTUAL;
+	return 1;
+}
+
+int lvm_replicator_lv_remove(struct logical_volume *lv)
+{
+	dm_list_del(&cow->snapshot->origin_list);
+	cow->snapshot->origin->origin_count--;
+
+	if (!lv_remove(cow->snapshot->lv)) {
+		log_error("Failed to remove internal snapshot LV %s",
+			  cow->snapshot->lv->name);
+		return 0;
+	}
+
+	cow->snapshot = NULL;
+
+	cow->vg->snapshot_count--;
+	cow->status |= VISIBLE_LV;
+
+	return 1;
+}
+#endif
+
+int lv_is_replicator(const struct logical_volume *lv)
+{
+	return ((lv->status & REPLICATOR) &&
+		!dm_list_empty(&lv->segments) &&
+		seg_is_replicator(first_seg(lv)));
+}
+
+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)));
+}
+
+int lv_is_rimage(const struct logical_volume *lv)
+{
+        return (lv->rdevice && lv->rdevice->lv == lv);
+}
+
+int lv_is_rlog(const struct logical_volume *lv)
+{
+	return (lv->status & REPLICATOR_LOG) &&
+		!dm_list_empty(&lv->segments) &&
+		seg_is_replicator(first_seg(lv));
+}
+
+int lv_is_slog(const struct logical_volume *lv)
+{
+	return (lv->rdevice && lv->rdevice->slog == lv);
+}
+
+int lv_is_active_replicator_dev(const struct logical_volume *lv)
+{
+	if (!(lv->status & REPLICATOR) ||
+	    !lv->rdevice || !lv->rdevice->rsite)
+		return 0;
+	return (lv->rdevice->rsite->state == REPLICATOR_STATE_ACTIVE);
+}
diff --git a/lib/metadata/segtype.h b/lib/metadata/segtype.h
index ff6fb08..4454cb2 100644
--- a/lib/metadata/segtype.h
+++ b/lib/metadata/segtype.h
@@ -35,8 +35,12 @@ 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_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)
@@ -106,6 +110,10 @@ struct segment_type *init_zero_segtype(struct cmd_context *cmd);
 struct segment_type *init_error_segtype(struct cmd_context *cmd);
 struct segment_type *init_free_segtype(struct cmd_context *cmd);
 
+#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..db1f9b7
--- /dev/null
+++ b/lib/replicator/Makefile.in
@@ -0,0 +1,28 @@
+#
+# Copyright (C) 2009 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@
+VPATH = @srcdir@
+
+SOURCES = replicator.c
+
+LIB_SHARED = liblvm2replicator.so
+
+include $(top_srcdir)/make.tmpl
+
+install: $(LIB_SHARED)
+	$(INSTALL) -D $(OWNER) $(GROUP) -m 555 $(STRIP) $< \
+		$(libdir)/$(LIB_SHARED).$(LIB_VERSION)
+	$(LN_S) -f $(LIB_SHARED).$(LIB_VERSION) \
+		$(libdir)/$(LIB_SHARED)
diff --git a/lib/replicator/replicator.c b/lib/replicator/replicator.c
new file mode 100644
index 0000000..6e0f7a6
--- /dev/null
+++ b/lib/replicator/replicator.c
@@ -0,0 +1,912 @@
+/*
+ * Copyright (C) 2009 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"
+#include "targets.h"  /* build_dlid */
+#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"
+
+#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: */
+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) {
+				log_very_verbose("Setting %s to %s",
+						 path, _state_txt[i]);
+				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 _action_txt[NUM_REPLICATOR_ACTION][8] = {
+	"warn",
+	"stall",
+	"drop",
+	"fail"
+};
+
+
+/* Parse action string */
+static replicator_action_t _get_action(const struct config_node *sn,
+				       const char *path, replicator_action_t def)
+{
+	char *str;
+	unsigned i;
+
+	if (get_config_str(sn, path, &str)) {
+		for (i = 0; i < sizeof(_action_txt)/sizeof(_action_txt[0]); ++i)
+			if (strcasecmp(str, _action_txt[i]) == 0) {
+				log_very_verbose("Setting %s to %s",
+						 path, _action_txt[i]);
+				return (replicator_action_t) i;
+			}
+		log_warn("%s: unknown value '%s', using default '%s' action",
+			 path, str, _action_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->async_action = REPLICATOR_ACTION_WARN;
+
+	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->async_action = _get_action(sn, "async_action",
+						  rsite->async_action);
+	}
+
+	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 (!lvm_replicator_add_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 (!lvm_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_uint64(sn, "highest_site_index", 0);
+
+	seg->region_size = _get_config_uint32(sn, "sync_log_size", 0);
+
+	for (; sn; sn = sn->sib)
+		if (!sn->v && !_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)
+{
+	const 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)
+		outf(f, "sync_log_size = %d", seg->region_size);
+
+	if (!dm_list_empty(&seg->lv->rsites))
+		out_newline(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->async_action != REPLICATOR_ACTION_WARN)
+			outf(f, "async_action = \"%s\"",
+			     _action_txt[rsite->async_action]);
+		if (rsite->fall_behind_timeout)
+			outf(f, "fall_behind_timeout = %u\t# seconds",
+			     rsite->fall_behind_timeout);
+		if (rsite->fall_behind_ios)
+			outf(f, "fall_behind_ios = %u\t# io operations",
+			     rsite->fall_behind_ios);
+		if (rsite->fall_behind_data)
+			outf(f, "fall_behind_data = %" PRIu64  "\t# bytes",
+			     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;
+	const struct replicator_site *rsite;
+	int action;
+
+	if (!seg->rlog_lv)
+		return_0;
+
+	if (!(rlog_dlid = build_dlid(dm, seg->rlog_lv->lvid.s, NULL)))
+		return_0;
+
+	dm_list_iterate_items(rsite, &seg->lv->rsites) {
+		action = (rsite->async_action == REPLICATOR_ACTION_WARN) ? DM_REPLICATOR_WARN :
+			(rsite->async_action == REPLICATOR_ACTION_STALL) ? DM_REPLICATOR_STALL :
+			(rsite->async_action == REPLICATOR_ACTION_DROP) ? DM_REPLICATOR_DROP : DM_REPLICATOR_FAIL;
+		if (!rsite->fall_behind_timeout && !rsite->fall_behind_data && !rsite->fall_behind_ios)
+			action = DM_REPLICATOR_SYNC;
+		if (!dm_tree_node_add_replicator_target(node,
+							seg->rlog_lv->size,
+							rlog_dlid,
+                                                        seg->rlog_type,
+							rsite->site_index,
+							action,
+							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, struct dm_pool *mem,
+				      struct cmd_context *cmd,
+				      struct lv_segment *seg,
+				      char *params, uint64_t *total_numerator,
+				      uint64_t *total_denominator)
+{
+	struct mirror_state *mirr_state;
+	uint64_t numerator, denominator;
+	unsigned mirror_count, m;
+	int used;
+	char *pos = params;
+
+	//if (!*target_state)
+	//	*target_state = _mirrored_init_target(mem, cmd);
+
+	mirr_state = *target_state;
+
+	/* Status line: <#mirrors> (maj:min)+ <synced>/<total_regions> */
+	log_debug("Replicator status: %s", params);
+
+	if (sscanf(pos, "%u %n", &mirror_count, &used) != 1) {
+		log_error("Failure parsing mirror status mirror count: %s.",
+			  params);
+		return 0;
+	}
+	pos += used;
+
+	for (m = 0; m < mirror_count; ++m) {
+		if (sscanf(pos, "%*x:%*x %n", &used) != 0) {
+			log_error("Failure parsing mirror status devices: %s.",
+				  params);
+			return 0;
+		}
+		pos += used;
+	}
+
+	if (sscanf(pos, "%" PRIu64 "/%" PRIu64 "%n", &numerator, &denominator,
+		   &used) != 2) {
+		log_error("Failure parsing replicator status fraction: %s.",
+			  params);
+		return 0;
+	}
+	pos += used;
+
+	*total_numerator += numerator;
+	*total_denominator += denominator;
+
+	if (seg)
+		seg->extents_copied = (uint32_t)(seg->area_len * numerator / 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;
+
+	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;
+
+	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)
+{
+	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;
+
+	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");
+		if (!(slog_lv = find_lv(seg->lv->vg, slog_str)))
+			return SEG_LOG_ERROR("Sync log %s not found in",
+					     slog_str);
+	}
+
+	// check for slog device in current VG
+
+	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;
+
+	if (!seg->lv->rdevice) {
+		lvm_replicator_dev_add_rimage(rdev, lv);
+		seg->lv->rdevice = rdev;
+	} else {
+		if (!slog_str ||
+		    !(rdev->slog_name = dm_pool_strdup(mem, slog_str)))
+			return_0;
+
+		lvm_replicator_dev_add_slog(rdev, slog_lv);
+	}
+
+	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;
+
+	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 (!lvm_replicator_add_dev(replicator, seg))
+		return_0;
+
+	log_very_verbose("replicator=%s", replicator->name);
+
+	// mandatory!!
+	if (!find_config_node(sn, "device_index"))
+		return SEG_LOG_ERROR("Missing device index for");
+
+	// read devices from sites
+	for (; sn; sn = sn->sib)
+		if (!(sn->v) && !_add_device(seg, sn->key, sn->child))
+			return 0;
+
+	if (seg->lv->rdevice)
+		seg->lv->rdevice->device_index = _get_config_uint64(sn, "device_index", 0);
+
+	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)
+{
+	const struct replicator_site *rsite;
+	const 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);
+
+	out_newline(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;
+	const struct replicator_device *rdev, *rdev_search;
+	const struct replicator_site *rsite;
+	char *rdev_path;	/* needed for write */
+	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_dlid(dm, 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_dlid(dm, 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 rdev list error");
+				return 0;
+			}
+		}
+
+		if (rdev->lv) {
+			if (!(rdev_dlid = build_dlid(dm, rdev->lv->lvid.s, NULL)))
+				return_0;
+		} else {
+			/* (?debug?) support remote device nodes */
+			if (!rdev->rsite->vg_name || !rdev->name)
+				return_0;
+
+			/* FIXME:
+			 * vg_read/_process_one_vg needs to be fixed to locate and lock remote vg
+			 * so we can use
+			 *   lv = find_lv(rdev->rsite->vg, rdev->name);
+			 *   if (!lv || !(rdev_dlid = build_dm_name(mem, rdev->rsite->vg, lv->lvid.s, NULL)))
+			 *       return_0;
+			 *
+                         * meanwhile use solution    vg_name + name
+			 */
+			if (!(rdev_path = dm_pool_alloc(mem, strlen(rdev->rsite->replicator->vg->cmd->dev_dir) +
+							strlen(rdev->rsite->vg_name) +
+							strlen(rdev->name) + 2)))
+				return_0;
+
+			sprintf(rdev_path, "%s%s/%s",
+				rdev->rsite->replicator->vg->cmd->dev_dir,
+				rdev->rsite->vg_name, rdev->name);
+			rdev_dlid = rdev_path;
+		}
+
+		slog_dlid = NULL;
+		/* using either disk or core (in memory) log */
+#if 0
+		/* HACK: avoid using slog device - currently kernel driver is broken */
+		slog_flags = DM_CORELOG | DM_FORCESYNC;
+		slog_size = 2048;
+#else
+		if (rdev->slog) {
+			slog_flags = DM_NOSYNC;
+			slog_size = rdev->slog->size;
+			if (!(slog_dlid = build_dlid(dm, rdev->slog->lvid.s, NULL)))
+				return_0;
+			slog_size = 2048; // FIXME: HACK
+		} 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
+		}
+
+#endif
+		if (!dm_tree_node_add_replicator_dev_target(node,
+							    seg->lv->size,
+							    replicator_dlid,
+							    seg->lv->rdevice->device_index,
+							    rdev_dlid,	/* rdev_uuid/path */
+							    rsite->site_index,
+							    slog_dlid,
+							    slog_flags,
+							    slog_size)) {
+			//if (seg->lv->rdevice->device_index == 0)
+			return_0;
+
+			/*
+			 * FIXME: add  'state = dropped'
+                         */
+
+			// CHECKME: is it fatal or just warning here ?? */
+			log_warn("Failed to add LV '%s' to replicator '%s'.",
+				 rdev->name, rsite->replicator->name);
+			return 1;
+		}
+	}
+
+	return 1;
+}
+
+/* FIXME write something useful for replicator here */
+static int _replicator_dev_target_percent(void **target_state,
+					  struct dm_pool *mem,
+					  struct cmd_context *cmd,
+					  struct lv_segment *seg,
+					  char *params,
+					  uint64_t *total_numerator,
+					  uint64_t *total_denominator)
+{
+	struct mirror_state *mirr_state;
+	uint64_t numerator, denominator;
+	unsigned mirror_count, m;
+	int used;
+	char *pos = params;
+
+	//if (!*target_state)
+	//	*target_state = _mirrored_init_target(mem, cmd);
+
+	mirr_state = *target_state;
+
+	/* Status line: <#mirrors> (maj:min)+ <synced>/<total_regions> */
+	log_debug("Replicator status: %s", params);
+
+	if (sscanf(pos, "%u %n", &mirror_count, &used) != 1) {
+		log_error("Failure parsing mirror status mirror count: %s.",
+			  params);
+		return 0;
+	}
+	pos += used;
+
+	for (m = 0; m < mirror_count; ++m) {
+		if (sscanf(pos, "%*x:%*x %n", &used) != 0) {
+			log_error("Failure parsing mirror status devices: %s.",
+				  params);
+			return 0;
+		}
+		pos += used;
+	}
+
+	if (sscanf(pos, "%" PRIu64 "/%" PRIu64 "%n", &numerator, &denominator,
+		   &used) != 2) {
+		log_error("Failure parsing replicator status fraction: %s.",
+			  params);
+		return 0;
+	}
+	pos += used;
+
+	*total_numerator += numerator;
+	*total_denominator += denominator;
+
+	if (seg)
+		seg->extents_copied = (uint32_t)(seg->area_len * numerator / 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 int _replicator_dev_modules_needed(struct dm_pool *mem,
+					  const struct lv_segment *seg __attribute((unused)),
+					  struct dm_list *modules)
+{
+	if (!str_list_add(mem, modules, REPLICATOR_DEV_MODULE))
+		return_0;
+
+	return 1;
+}
+
+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_dev_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.6.5.rc2




More information about the lvm-devel mailing list