Skip to contentSkip to conversation

Replicator 100707

PATCH New Zdenek Kabelac 1 participant 23 messages Jul 7, 2010

lore
Share & tools
lore
#0 lore raw

cover Replicator 100707

This patchset enhances lvm with replicator metadata construction. It 'should not' influence other commands.

Use case example:

# build remote devices
vgcreate vg_ny /dev/loop1
vgcreate vg_paris /dev/loop2

lvcreate -L10M -n L1 vg_ny
lvcreate -L10M -n L1 vg_paris
lvcreate -L20M -n L2 vg_ny
lvcreate -L20M -n L2 vg_paris

# build local replicator
vgcreate my /dev/loop0
lvcreate --replicator rep -L20M my

lvcreate --site Berlin --replicator my/rep
lvcreate --site NY --remotevg vg_ny --replicator my/rep lvcreate --site Paris --remotevg vg_paris --replicator my/rep

lvcreate --replicatordev -L10M -n L1 --replicator my/rep lvcreate --replicatordev -L20M -n L2 --replicator my/rep

lvcreate --replicator rep -L20M my || exit 1 lvcreate --replicatordev -L10M -n L1 --replicator my/rep

lvremove my/L1

Note: after removing 'L1' LV 'L1_rimage' and '_slog' devices are left in VG Ideally user should use own 'VG'
and for removal just run:

vgremove my

lvchange --site Berlin --replicator my/rep -ay
== lvchange --site Berlin my/L1 -ay
== lvchange --site Berlin my/rep -ay

Zdenek Kabelac (22):
Add units to passed parameters data & timeout Use size
Allow the user to not specify a size when creating snapshot. Skip check missing rem.VGs for non-activate locks
Replicator: check for active replicator
Replicator: add reserved names
Replicator: man page update for lvm
Replicator: add _replicator_in_sync
Replicator: add report for replicator targets
Replicator: improve detection of replicator-dev
Replicator: new defaults
Replicator: metadata update
Replicator: replicator_manip changes
Replicator: replicator.c changes
Replicator: add new command option read functions
Replicator: new args
Replicator: read site_params
Replicator: lv_manip - create replicator
Replicator: lvcreate implementation
Replicator: man page update for lvcreate
Replicator: lvchange implementation
Replicator: man page update for lvchange
Replicator: lvremove implementation

 lib/config/defaults.h            |    9 +
 lib/locking/locking.h            |    2 +-
 lib/metadata/lv_manip.c          |  126 ++++-
 lib/metadata/merge.c             |   18 +-
 lib/metadata/metadata-exported.h |   59 ++-
 lib/metadata/replicator_manip.c  | 1211 +++++++++++++++++++++++++++++++-------
 lib/misc/lvm-globals.c           |   11 +
 lib/misc/lvm-globals.h           |    2 +
 lib/misc/lvm-string.c            |   18 +
 lib/replicator/replicator.c      |  178 ++----
 lib/report/columns.h             |    2 +
 lib/report/report.c              |   32 +
 libdm/libdm-deptree.c            |    4 +-
 man/lvchange.8.in                |   31 +
 man/lvcreate.8.in                |   76 +++
 man/lvm.8.in                     |    3 +-
 tools/args.h                     |   10 +
 tools/commands.h                 |   18 +-
 tools/lvchange.c                 |  195 ++++++-
 tools/lvcreate.c                 |  137 +++++-
 tools/lvmcmdline.c               |   24 +
 tools/lvremove.c                 |   19 +-
 tools/toollib.c                  |  111 ++++
 tools/toollib.h                  |    3 +
 tools/tools.h                    |    2 +
 tools/vgchange.c                 |    2 +-
 26 files changed, 1942 insertions(+), 361 deletions(-)
#1 lore raw

PATCH 1/22 Add units to passed parameters data & timeout Use size

---
 libdm/libdm-deptree.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)
libdm/libdm-deptree.c +2 -2
index fac9d21..ff714d9 100644
@@ -1520,11 +1520,11 @@ static int _replicator_emit_segment_line(const struct load_segment *seg, char *p
 			    (rsite->mode == DM_REPLICATOR_SYNC) ? "synchronous" : "asynchronous");
 
 		if (rsite->fall_behind_data)
-			EMIT_PARAMS(*pos, " data %" PRIu64, rsite->fall_behind_data);
+			EMIT_PARAMS(*pos, " size %" PRIu64 "s", rsite->fall_behind_data);
 		else if (rsite->fall_behind_ios)
 			EMIT_PARAMS(*pos, " ios %" PRIu32, rsite->fall_behind_ios);
 		else if (rsite->async_timeout)
-			EMIT_PARAMS(*pos, " timeout %" PRIu32, rsite->async_timeout);
+			EMIT_PARAMS(*pos, " timeout %" PRIu32 "s", rsite->async_timeout);
 	}
 
 	return 1;
Signature · 1 line
1.7.1.1
#2 lore raw

PATCH 2/22 Allow the user to not specify a size when creating snapshot.

In reply to Zdenek Kabelac

For shared snapshot, the size is not required. If the user creates other volume than a shared snapshot, zero size will be rejected in lv_create_single.

---
 tools/lvcreate.c |    4 ++++
 1 files changed, 4 insertions(+), 0 deletions(-)
tools/lvcreate.c +4 -0
index d0e962f..9e167aa 100644
@@ -191,6 +191,9 @@ static int _read_size_params(struct lvcreate_params *lp,
 			     struct lvcreate_cmdline_params *lcp,
 			     struct cmd_context *cmd)
 {
+	if (!arg_count(cmd, extents_ARG) && !arg_count(cmd, size_ARG))
+		goto skip_size_arg;
+
 	if (arg_count(cmd, extents_ARG) + arg_count(cmd, size_ARG) != 1) {
 		log_error("Please specify either size or extents (not both)");
 		return 0;
@@ -215,6 +218,7 @@ static int _read_size_params(struct lvcreate_params *lp,
 		lcp->percent = PERCENT_NONE;
 	}
 
+skip_size_arg:
 	/* Size returned in kilobyte units; held in sectors */
 	if (arg_count(cmd, virtualsize_ARG)) {
 		if (arg_sign_value(cmd, virtualsize_ARG, 0) == SIGN_MINUS) {
Signature · 1 line
1.7.1.1
#3 lore raw

PATCH 3/22 Skip check missing rem.VGs for non-activate locks

In reply to Zdenek Kabelac

Skip call for checking whether this LV needs to locks some more remote VGs (applies to replicator_dev devices).

The effect is, that deactivation of replicator-dev devices does not require to take a lock for remote VGs, so avoids repeated invoke of deactivate_lv.

---
 lib/locking/locking.h |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
lib/locking/locking.h +1 -1
index 488d194..dde1a08 100644
@@ -136,7 +136,7 @@ int check_lvm1_vg_inactive(struct cmd_context *cmd, const char *vgname);
 	(vg_is_clustered((lv)->vg) ? LCK_CLUSTER_VG : 0)
 
 #define lock_lv_vol(cmd, lv, flags)	\
-	(find_replicator_vgs((lv)) ? \
+	((!((flags) & LCK_READ) || find_replicator_vgs((lv))) ? \
 		lock_vol(cmd, (lv)->lvid.s, flags | LCK_LV_CLUSTERED(lv)) : \
 		0)
 
Signature · 1 line
1.7.1.1
#4 lore raw

PATCH 4/22 Replicator: check for active replicator

In reply to Zdenek Kabelac

Skip activation of other heads only for a active replicator. For inactive active all heads with linear overlay mapping

---
 tools/vgchange.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
tools/vgchange.c +1 -1
index ed5a7ef..840552a 100644
@@ -106,7 +106,7 @@ static int _activate_lvs_in_vg(struct cmd_context *cmd,
 
 		/* Only request activation of the first replicator-dev LV */
 		/* Avoids retry with all heads in case of failure */
-		if (lv_is_replicator_dev(lv) && (lv != first_replicator_dev(lv)))
+		if (lv_is_active_replicator_dev(lv) && (lv != first_replicator_dev(lv)))
 			continue;
 
 		/* Can't deactivate a pvmove LV */
Signature · 1 line
1.7.1.1
#5 lore raw

PATCH 5/22 Replicator: add reserved names

In reply to Zdenek Kabelac

Add new reserved names for replicator related devices.

---
 lib/misc/lvm-string.c |   18 ++++++++++++++++++
 1 files changed, 18 insertions(+), 0 deletions(-)
lib/misc/lvm-string.c +18 -0
index 7eed799..fb73674 100644
@@ -275,6 +275,24 @@ int apply_lvname_restrictions(const char *name)
 		return 0;
 	}
 
+	if (strstr(name, "_slog")) {
+		log_error("Names including \"_slog\" are reserved. "
+			  "Please choose a different LV name.");
+		return 0;
+	}
+
+	if (strstr(name, "_rlog")) {
+		log_error("Names including \"_rlog\" are reserved. "
+			  "Please choose a different LV name.");
+		return 0;
+	}
+
+	if (strstr(name, "_rimage")) {
+		log_error("Names including \"_rimage\" are reserved. "
+			  "Please choose a different LV name.");
+		return 0;
+	}
+
 	return 1;
 }
 
Signature · 1 line
1.7.1.1
#6 lore raw

PATCH 6/22 Replicator: man page update for lvm

In reply to Zdenek Kabelac

Add new reserved names to lvm man page.

---
 man/lvm.8.in |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)
man/lvm.8.in +2 -1
index e38ce4f..7d070f7 100644
@@ -271,7 +271,8 @@ The following characters are valid for VG and LV names:
 VG and LV names cannot begin with a hyphen.
 There are also various reserved names that are used internally by lvm that can not be used as LV or VG names.
 A VG cannot be called anything that exists in /dev/ at the time of creation, nor can it be called '.' or '..'.
-A LV cannot be called '.' '..' 'snapshot' or 'pvmove'. The LV name may also not contain the strings '_mlog' or '_mimage'
+A LV cannot be called '.' '..' 'snapshot' or 'pvmove'. The LV name may also not contain the strings 
+'_mlog', '_mimage', '_rlog', '_slog', '_rimage'.
 
 
 .SH DIAGNOSTICS
Signature · 1 line
1.7.1.1
#7 lore raw

PATCH 7/22 Replicator: add _replicator_in_sync

In reply to Zdenek Kabelac

Add function init_replicator_in_sync() to be similar as mirror. For now this function is not functional.

---
 lib/misc/lvm-globals.c |   11 +++++++++++
 lib/misc/lvm-globals.h |    2 ++
 2 files changed, 13 insertions(+), 0 deletions(-)
lib/misc/lvm-globals.c +11 -0
index 8dc2b02..5334691 100644
@@ -34,6 +34,7 @@ static int _ignorelockingfailure = 0;
 static int _security_level = SECURITY_LEVEL;
 static char _cmd_name[30] = "";
 static int _mirror_in_sync = 0;
+static int _replicator_in_sync = 0;
 static int _dmeventd_monitor = DEFAULT_DMEVENTD_MONITOR;
 static int _background_polling = DEFAULT_BACKGROUND_POLLING;
 static int _ignore_suspended_devices = 0;
@@ -88,6 +89,11 @@ void init_mirror_in_sync(int in_sync)
 	_mirror_in_sync = in_sync;
 }
 
+void init_replicator_in_sync(int in_sync)
+{
+	_replicator_in_sync = in_sync;
+}
+
 void init_dmeventd_monitor(int reg)
 {
 	_dmeventd_monitor = reg;
@@ -190,6 +196,11 @@ int mirror_in_sync(void)
 	return _mirror_in_sync;
 }
 
+int replicator_in_sync(void)
+{
+	return _replicator_in_sync;
+}
+
 int dmeventd_monitor_mode(void)
 {
 	return _dmeventd_monitor;
lib/misc/lvm-globals.h +2 -0
index 0134c32..c08aa2e 100644
@@ -31,6 +31,7 @@ void init_ignorelockingfailure(int level);
 void init_lockingfailed(int level);
 void init_security_level(int level);
 void init_mirror_in_sync(int in_sync);
+void init_replicator_in_sync(int in_sync);
 void init_dmeventd_monitor(int reg);
 void init_background_polling(int polling);
 void init_ignore_suspended_devices(int ignore);
@@ -51,6 +52,7 @@ int ignorelockingfailure(void);
 int lockingfailed(void);
 int security_level(void);
 int mirror_in_sync(void);
+int replicator_in_sync(void);
 int background_polling(void);
 int ignore_suspended_devices(void);
 const char *log_command_name(void);
Signature · 1 line
1.7.1.1
#8 lore raw

PATCH 8/22 Replicator: add report for replicator targets

In reply to Zdenek Kabelac

Elementary reporting tool for replicator and replicato-dev LVs. Replicator uses free flag 'q'.
Replicator-dev 'r' for normal, 'R' for unsynchronized replicator.
Note: unsychronized status not yet written.

---
 lib/report/columns.h |    2 ++
 lib/report/report.c  |   32 ++++++++++++++++++++++++++++++++
 2 files changed, 34 insertions(+), 0 deletions(-)
lib/report/columns.h +2 -0
index 823ce2c..b6e00ef 100644
@@ -76,6 +76,8 @@ FIELD(LVS, lv, STR, "Convert", lvid, 7, convertlv, "convert_lv", "For lvconvert,
 FIELD(LVS, lv, STR, "LV Tags", tags, 7, tags, "lv_tags", "Tags, if any.")
 FIELD(LVS, lv, STR, "Log", lvid, 3, loglv, "mirror_log", "For mirrors, the LV holding the synchronisation log.")
 FIELD(LVS, lv, STR, "Modules", lvid, 7, modules, "modules", "Kernel device-mapper modules required for this LV.")
+FIELD(LVS, lv, STR, "RImage", lvid, 7, rimage, "rimage", "For replicators, the replicated image of this LV.")
+FIELD(LVS, lv, STR, "Replicator", lvid, 7, replicator, "replicator", "For replicators, the replicator control LV.")
 
 FIELD(LABEL, pv, STR, "Fmt", id, 3, pvfmt, "pv_fmt", "Type of metadata.")
 FIELD(LABEL, pv, STR, "PV UUID", id, 38, uuid, "pv_uuid", "Unique identifier.")
lib/report/report.c +32 -0
index 9a76334..b7fb15b 100644
@@ -303,6 +303,10 @@ static int _lvstatus_disp(struct dm_report *rh __attribute((unused)), struct dm_
 		repstr[0] = 'p';
 	else if (lv->status & CONVERTING)
 		repstr[0] = 'c';
+	else if (lv_is_replicator(lv))
+		repstr[0] = 'q';
+	else if (lv_is_replicator_dev(lv))
+		repstr[0] = (lv->status & REPLICATOR_NOTSYNCED) ? 'R' : 'r';
 	else if (lv->status & VIRTUAL)
 		repstr[0] = 'v';
 	/* Origin takes precedence over Mirror */
@@ -605,6 +609,34 @@ static int _convertlv_disp(struct dm_report *rh, struct dm_pool *mem __attribute
 	return 1;
 }
 
+static int _rimage_disp(struct dm_report *rh, struct dm_pool *mem,
+			struct dm_report_field *field,
+			const void *data, void *private)
+{
+	const struct logical_volume *lv = (const struct logical_volume *) data;
+
+	if (lv_is_replicator_dev(lv))
+		return _lvname_disp(rh, mem, field, lv->rdevice->lv, private);
+
+	dm_report_field_set_value(field, "", NULL);
+
+	return 1;
+}
+
+static int _replicator_disp(struct dm_report *rh, struct dm_pool *mem,
+			struct dm_report_field *field,
+			const void *data, void *private)
+{
+	const struct logical_volume *lv = (const struct logical_volume *) data;
+
+	if (lv_is_replicator_dev(lv))
+		return _lvname_disp(rh, mem, field, lv->rdevice->rsite->replicator, private);
+
+	dm_report_field_set_value(field, "", NULL);
+
+	return 1;
+}
+
 static int _size32_disp(struct dm_report *rh __attribute((unused)), struct dm_pool *mem,
 			struct dm_report_field *field,
 			const void *data, void *private)
Signature · 1 line
1.7.1.1
#9 lore raw

PATCH 9/22 Replicator: improve detection of replicator-dev

In reply to Zdenek Kabelac

Check for NULL replicator pointer in replicator-dev segment.

---
 lib/metadata/merge.c |   18 ++++++++++++------
 1 files changed, 12 insertions(+), 6 deletions(-)
lib/metadata/merge.c +12 -6
index 3b8895c..11c58f9 100644
@@ -219,14 +219,20 @@ int check_lv_segments(struct logical_volume *lv, int complete_vg)
 				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 (!seg->replicator) {
+				log_error("LV %s has replicator-dev segment "
+					  "without replicator", lv->name);
+				inc_error_count;
+			} else {
+				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 (lv == seg->replicator)
-				seg_found++;
 		}
 		if (seg_is_replicator(seg) && lv == seg->rlog_lv)
 				seg_found++;
Signature · 1 line
1.7.1.1
#10 lore raw

PATCH 10/22 Replicator: new defaults

In reply to Zdenek Kabelac
---
 lib/config/defaults.h |    9 +++++++++
 1 files changed, 9 insertions(+), 0 deletions(-)
lib/config/defaults.h +9 -0
index 3d8881c..fc5649e 100644
@@ -48,6 +48,14 @@
 #define DEFAULT_DMEVENTD_MONITOR 1
 #define DEFAULT_BACKGROUND_POLLING 1
 
+#define DEFAULT_REPLICATOR_SYNCLOG "disk"
+#define DEFAULT_REPLICATOR_LOG_TYPE "ringbuffer"
+#define DEFAULT_REPLICATOR_LOCAL_SITE_NAME "local"
+#define DEFAULT_REPLICATOR_FALL_BEHIND_DATA 0
+#define DEFAULT_REPLICATOR_FALL_BEHIND_IOS 0
+#define DEFAULT_REPLICATOR_FALL_BEHIND_TIMEOUT 0
+#define DEFAULT_REPLICATOR_ASYNC_MODE (DM_REPLICATOR_ASYNC_WARN)
+
 #define DEFAULT_UMASK 0077
 
 #ifdef LVM1_FALLBACK
@@ -106,6 +114,7 @@
 
 #define DEFAULT_STRIPE_FILLER "error"
 #define DEFAULT_MIRROR_REGION_SIZE 512	/* KB */
+#define DEFAULT_REPLICATOR_REGION_SIZE 512	/* KB */
 #define DEFAULT_INTERVAL 15
 
 #ifdef READLINE_SUPPORT
Signature · 1 line
1.7.1.1
#11 lore raw

PATCH 11/22 Replicator: metadata update

In reply to Zdenek Kabelac
---
 lib/metadata/metadata-exported.h |   59 ++++++++++++++++++++++++++++++--------
 1 files changed, 47 insertions(+), 12 deletions(-)
lib/metadata/metadata-exported.h +47 -12
index 7824005..cb7fd3d 100644
@@ -74,6 +74,7 @@
 
 #define REPLICATOR		0x20000000U	/* LV -internal use only for replicator */
 #define REPLICATOR_LOG		0x40000000U	/* LV -internal use only for replicator-dev */
+#define REPLICATOR_NOTSYNCED   	0x80000000U	/* LV -internal use only for replicator */
 
 #define LVM_READ              	0x00000100U	/* LV VG */
 #define LVM_WRITE             	0x00000200U	/* LV VG */
@@ -352,7 +353,7 @@ struct replicator_device {
 	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 */
+	uint32_t slog_core;		/* Corelog size */
 };
 /* -- Replicator datatypes */
 
@@ -622,6 +623,8 @@ uint64_t extents_from_size(struct cmd_context *cmd, uint64_t size,
 struct lvcreate_params {
 	/* flags */
 	int snapshot; /* snap */
+	const char *replicator; /* replicator */
+	int replicator_dev; /* replicator-dev */
 	int zero; /* all */
 	int major; /* all */
 	int minor; /* all */
@@ -640,6 +643,9 @@ struct lvcreate_params {
 
 	uint32_t mirrors; /* mirror */
 
+	const char *rlog_type; /* replicator */
+	struct replicator_site rsite; /* replicator, use only parameters */
+
 	const struct segment_type *segtype; /* all */
 
 	/* size */
@@ -803,24 +809,53 @@ 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 replicator_site *find_site_in_replicator(const struct logical_volume *replicator,
+						const char *site_name);
+struct replicator_site *find_local_site_in_replicator(const struct logical_volume *replicator);
 struct logical_volume *first_replicator_dev(const struct logical_volume *lv);
+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_site_add_device(struct replicator_site *rsite,
+			       struct lv_segment *replicator_dev_seg,
+			       const char *name,
+			       struct logical_volume *rimage,
+			       uint32_t slog_core,
+			       struct logical_volume *slog_lv,
+			       uint64_t device_index);
+int replicator_site_set_op_mode(struct replicator_site *rsite, const char *sitemode);
+const char *replicator_site_get_op_mode(const struct replicator_site *rsite);
+struct replicator_site *replicator_add_site(struct logical_volume *replicator,
+					    const char *site_name);
+void replicator_init(struct logical_volume *replicator);
+int replicator_add_replicator_dev(struct logical_volume *replicator,
+				  struct lv_segment *rdev_seg);
+
+int lv_add_replicator_dev(struct logical_volume *replicator,
+			  struct logical_volume *lv);
+int lv_remove_replicator_dev(struct logical_volume *replicator_dev);
+
+int lv_add_replicator_site(struct logical_volume *replicator,
+			   const struct replicator_site *rsite);
+int lv_remove_replicator_site(struct logical_volume *replicator, const char *site_name);
+
+int lv_add_sync_log(struct logical_volume *replicator,
+		    unsigned site_index,
+		    uint64_t device_index,
+		    struct dm_list *allocatable_pvs,
+		    alloc_policy_t alloc);
+
+int vg_prearrange_replicator(struct volume_group *vg,
+			     const struct lvcreate_params *lp);
+int vg_add_replicator(struct logical_volume *replicator,
+		      const char *rlog_type,
+		      uint32_t region_size);
+int vg_remove_replicator(struct logical_volume *replicator);
 /* --  metadata/replicator_manip.c */
 struct cmd_vg *cmd_vg_add(struct dm_pool *mem, struct dm_list *cmd_vgs,
 			  const char *vg_name, const char *vgid,
Signature · 1 line
1.7.1.1
#12 lore raw

PATCH 12/22 Replicator: replicator_manip changes

In reply to Zdenek Kabelac

Changes for replicator_manip.c source file.

Adding new API functions.

Lots of lines for log creation are copied from mirror code and then are adapted for _slog. Code is done with hope we could share same parametrized code later for both targets - mirror and replicator. But with recent changes to mirrored logs it is a harder task.

---
 lib/metadata/replicator_manip.c | 1211 ++++++++++++++++++++++++++++++++-------
 1 files changed, 1001 insertions(+), 210 deletions(-)
lib/metadata/replicator_manip.c +1001 -210
index b3a2fff..b2c4eda 100644
@@ -15,244 +15,741 @@
 #include "lib.h"
 #include "locking.h"
 #include "metadata.h"
+#include "defaults.h"
 #include "segtype.h"
 #include "toolcontext.h"
+#include "activate.h"
+#include "archiver.h"
+#include "lv_alloc.h"
+#include "str_list.h"
+
+static const struct {
+	const char name[8];
+	int value;
+} dm_op_mode_table[] = {
+	{ "sync", DM_REPLICATOR_SYNC },
+	{ "warn", DM_REPLICATOR_ASYNC_WARN },
+	{ "stall", DM_REPLICATOR_ASYNC_STALL },
+	{ "drop", DM_REPLICATOR_ASYNC_DROP },
+	{ "fail", DM_REPLICATOR_ASYNC_FAIL }
+};
 
-/* Add lv as replicator_dev device */
-int replicator_dev_add_rimage(struct replicator_device *rdev,
-			      struct logical_volume *lv)
+/**
+ * Tests whether LV is member of an active replicator.
+ *
+ * \param lv    Logical volume for testing
+ *
+ * \return	Returns 1 if the lv is member of an active replicator,
+ *		0 otherwise.
+ */
+int lv_is_active_replicator_dev(const struct logical_volume *lv)
 {
-	if (!lv || !rdev)
-		return_0;
+	return (lv_is_replicator_dev(lv) &&
+		lv->rdevice &&
+		lv->rdevice->rsite &&
+		lv->rdevice->rsite->state == REPLICATOR_STATE_ACTIVE);
+}
+
+/**
+ * Tests whether LV is replicator control device.
+ * (Segment-less LV could be also replicator.)
+ *
+ * \param lv    Logical volume for testing
+ *
+ * \return	Returns 1 if the lv is replicator control device,
+ *		0 otherwise.
+ */
+int lv_is_replicator(const struct logical_volume *lv)
+{
+	return ((lv->status & REPLICATOR) &&
+		(dm_list_empty(&lv->segments) ||
+		 seg_is_replicator(first_seg(lv))));
+}
+
+/**
+ * Tests whether LV is replicator device.
+ *
+ * \param lv    Logical volume for testing
+ *
+ * \return	Returns 1 if the lv is replicator device,
+ *		0 otherwise.
+ */
+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)));
+}
+
+/**
+ * Tests whether LV is replicated rimage device.
+ *
+ * \param lv    Logical volume for testing
+ *
+ * \return	Returns 1 if the lv is replicated rimage device,
+ *		0 otherwise.
+ */
+int lv_is_rimage(const struct logical_volume *lv)
+{
+	return (!lv_is_replicator_dev(lv) &&
+		(lv->rdevice && lv->rdevice->lv == lv));
+}
+
+/**
+ * Tests whether LV is replicator log device.
+ *
+ * \param lv    Logical volume for testing
+ *
+ * \return	Returns 1 if the lv is replicator log device,
+ *		0 otherwise.
+ */
+int lv_is_rlog(const struct logical_volume *lv)
+{
+	return (lv->status & REPLICATOR_LOG);
+}
+
+/**
+ * Tests whether LV is replicator sync log device.
+ *
+ * \param lv    Logical volume for testing
+ *
+ * \return	Returns 1 if the lv is replicator sync log device,
+ *		0 otherwise.
+ */
+int lv_is_slog(const struct logical_volume *lv)
+{
+	return (lv->rdevice && lv->rdevice->slog == lv);
+}
+
+/**
+ * Returns local site from replicator.
+ */
+struct replicator_site *find_local_site_in_replicator(const struct logical_volume *replicator)
+{
+	struct replicator_site *rsite;
 
+	dm_list_iterate_items(rsite, &replicator->rsites)
+		if (rsite->site_index == 0)
+			return rsite;
+
+	return NULL;
+}
+
+/**
+ * Returns site with name site_name from replicator.
+ */
+struct replicator_site *find_site_in_replicator(const struct logical_volume *replicator,
+						const char *site_name)
+{
+	struct replicator_site *rsite;
+
+	dm_list_iterate_items(rsite, &replicator->rsites)
+		if (strcmp(rsite->name, site_name) == 0)
+			return rsite;
+
+	return NULL;
+}
+
+/**
+ * Returns first replicator-dev in site in case the LV is replicator-dev
+ * or replicator, NULL otherwise
+ */
+struct logical_volume *first_replicator_dev(const struct logical_volume *lv)
+{
+	struct replicator_device *rdev;
+	struct replicator_site *rsite;
+	const struct logical_volume *replicator;
+
+	if (lv_is_replicator_dev(lv))
+		replicator = first_seg(lv)->replicator;
+	else if (lv_is_replicator(lv))
+		replicator = lv;
+	else {
+		log_error(INTERNAL_ERROR "Logical volume %s is not "
+			  "replicator", lv->name);
+		return NULL;
+	}
+
+	if ((rsite = find_local_site_in_replicator(replicator)))
+		dm_list_iterate_items(rdev, &rsite->rdevices)
+			return rdev->replicator_dev->lv;
+
+	return NULL;
+}
+
+/* Add lv as replicator_dev device */
+static int _replicator_device_add_rimage(struct replicator_device *rdev,
+					 struct logical_volume *lv)
+{
 	if (lv_is_rimage(lv)) {
-		log_error("Logical volume %s is already part of other "
-			  "replicator.", lv->name);
+		log_error(INTERNAL_ERROR "Logical volume %s is used by replicator %s.",
+			  lv->name, lv->rdevice->rsite->replicator->name);
 		return 0;
 	}
 
 	if (rdev->lv) {
-		log_error("Logical volume %s can not be attached to an "
+		log_error(INTERNAL_ERROR "Logical volume %s cannot be attached to an "
 			  "already defined replicator device", lv->name);
 		return 0;
 	}
 
 	lv_set_hidden(lv);
 	lv->rdevice = rdev;
+	rdev->replicator_dev->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)
+static struct logical_volume *_replicator_device_remove_rimage(struct replicator_device *rdev)
 {
-	struct logical_volume *lv;
+	struct logical_volume *rimage = rdev->lv;
 
-	if (!rdev || !rdev->lv)
-		return_NULL;
+	if (!rimage || !lv_is_rimage(rimage)) {
+		log_error(INTERNAL_ERROR "Replicator device in site %s "
+			  "does not have rimage.", rdev->rsite->name);
+		return NULL;
+	}
 
-	lv = rdev->lv;
-	if (!remove_seg_from_segs_using_this_lv(lv, rdev->replicator_dev))
+	if (!remove_seg_from_segs_using_this_lv(rimage, rdev->replicator_dev))
 		return_NULL;
 
-	/* FIXME: - check for site references */
 	rdev->lv = NULL;
-	lv->rdevice = NULL;
-	lv_set_visible(lv);
+	rimage->rdevice = NULL;
+	lv_set_visible(rimage);
 
-	return lv;
+	return rimage;
 }
 
-int replicator_dev_add_slog(struct replicator_device *rdev,
-			    struct logical_volume *slog)
+static int _replicator_device_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);
+	if (lv_is_slog(slog)) {
+		log_error(INTERNAL_ERROR "Logical volume %s cannot be used.",
+			  slog->name);
 		return 0;
 	}
 
-	if (slog->rdevice) {
-		log_error("Sync log %s is already used by replicator %s.",
-			  slog->name, slog->rdevice->rsite->replicator->name);
+	if (rdev->slog) {
+		log_error(INTERNAL_ERROR "Replicator device in site %s has "
+			  "sync log %s.", rdev->rsite->name, rdev->slog->name);
 		return 0;
 	}
 
+	if (!add_seg_to_segs_using_this_lv(slog, rdev->replicator_dev))
+		return_0;
+
 	lv_set_hidden(slog);
-	slog->rdevice = rdev;
 	rdev->slog = slog;
+	slog->rdevice = rdev;
 
-	return add_seg_to_segs_using_this_lv(slog, rdev->replicator_dev);
+	return 1;
 }
 
-struct logical_volume *replicator_dev_remove_slog(struct replicator_device *rdev)
+static struct logical_volume *_replicator_device_remove_slog(struct replicator_device *rdev)
 {
-	struct logical_volume *lv;
+	struct logical_volume *slog = rdev->slog;
+
+	if (!slog || !lv_is_slog(slog)) {
+		log_error(INTERNAL_ERROR "Replicator device in site %s "
+			  "does not have sync log.", rdev->rsite->name);
+		return NULL;
+	}
 
-	if (!rdev)
+	slog->rdevice = NULL;
+	rdev->slog = NULL;
+	lv_set_visible(slog);
+
+	if (!remove_seg_from_segs_using_this_lv(slog, rdev->replicator_dev))
 		return_NULL;
 
-	lv = rdev->slog;
-	if (!lv) {
-		log_error("Replicator device in site %s does not have sync log.",
-			  rdev->rsite->name);
+	return slog;
+}
+
+static char *_replicator_device_slog_name(struct logical_volume *replicator,
+					  unsigned site_index,
+					  uint64_t device_index)
+{
+	char *name;
+	size_t len = strlen(replicator->name) + 12 + 22 + 10;
+
+	if (!(name = dm_pool_zalloc(replicator->vg->vgmem, len))) {
+		log_error("Allocation of slog name failed.");
+		return NULL;
+	}
+
+	if (!dm_snprintf(name, len, "%s_%u_%" PRIu64 "_slog", replicator->name,
+			 site_index, device_index) < 0) {
+		log_error("Error in name creation");
+		return NULL;
+	}
+
+	return name;
+}
+
+int replicator_add_rlog(struct lv_segment *replicator_seg,
+			struct logical_volume *rlog_lv)
+{
+	if (lv_is_rlog(rlog_lv)) {
+		log_error(INTERNAL_ERROR "Logical volume %s cannot be used.",
+			  rlog_lv->name);
+		return 0;
+	}
+
+	if (!add_seg_to_segs_using_this_lv(rlog_lv, replicator_seg))
+		return_0;
+
+	lv_set_hidden(rlog_lv);
+	rlog_lv->status |= REPLICATOR_LOG;
+	replicator_seg->rlog_lv = rlog_lv;
+
+	return 1;
+}
+
+struct logical_volume *replicator_remove_rlog(struct lv_segment *replicator_seg)
+{
+	struct logical_volume *rlog_lv = replicator_seg->rlog_lv;
+
+	if (!rlog_lv || !lv_is_rlog(rlog_lv)) {
+		log_error(INTERNAL_ERROR "Replicator %s does not have rlog.",
+			  replicator_seg->lv->name);
 		return NULL;
 	}
 
-	if (!remove_seg_from_segs_using_this_lv(lv, rdev->replicator_dev))
+	replicator_seg->rlog_lv = NULL;
+	rlog_lv->status &= ~REPLICATOR_LOG;
+	lv_set_visible(rlog_lv);
+
+	if (!remove_seg_from_segs_using_this_lv(rlog_lv, replicator_seg))
 		return_NULL;
 
-	rdev->slog = NULL;
-	lv->rdevice = NULL;
-	lv_set_visible(lv);
+	return rlog_lv;
+}
+
+/**
+ *
+ */
+int replicator_site_add_device(struct replicator_site *rsite,
+			       struct lv_segment *replicator_dev_seg,
+			       const char *name,
+			       struct logical_volume *rimage,
+			       uint32_t slog_core,
+			       struct logical_volume *slog,
+			       uint64_t device_index)
+{
+	struct dm_pool *mem = replicator_dev_seg->lv->vg->vgmem;
+	struct replicator_device *rdev;
+
+	if (!(rdev = dm_pool_zalloc(mem, sizeof(*rdev)))) {
+		log_error("Allocation of replicator device failed.");
+		return 0;
+	}
+
+	if (!(rdev->name = dm_pool_strdup(mem, name))) {
+		log_error("Allocation of replicator device name failed.");
+		return 0;
+	}
+
+	log_very_verbose("Created %s/%s", rsite->name, rdev->name);
+
+	rdev->rsite = rsite;
+	rdev->replicator_dev = replicator_dev_seg;
+	rdev->device_index = device_index;
+	rdev->slog_core = slog_core;
+
+	dm_list_add(&rsite->rdevices, &rdev->list);// linked site list
+
+	if (rimage && !_replicator_device_add_rimage(rdev, rimage))
+		return_0;
+
+	if (slog_core && slog) {
+		log_error("Either slog or corelog must be used.");
+		return 0;
+	}
 
-	return lv;
+	if (slog && !_replicator_device_add_slog(rdev, slog))
+		return_0;
+
+	return 1;
 }
 
-int replicator_add_replicator_dev(struct logical_volume *replicator_lv,
-				  struct lv_segment *replicator_dev_seg)
+static int _replicator_site_remove_device(struct replicator_device *rdev)
 {
-	if (!replicator_lv)
+	if (rdev->lv && !_replicator_device_remove_rimage(rdev))
 		return_0;
 
-	if (!(replicator_lv->status & REPLICATOR)) {
-		dm_list_init(&replicator_lv->rsites);
-		lv_set_hidden(replicator_lv);
-		replicator_lv->status |= REPLICATOR;
+	if (rdev->slog && !_replicator_device_remove_slog(rdev))
+		return_0;
+
+	dm_list_del(&rdev->list);
+
+	return 1;
+}
+
+struct replicator_site *replicator_add_site(struct logical_volume *replicator,
+					    const char *site_name)
+{
+	struct replicator_site *rsite;
+
+	if (find_site_in_replicator(replicator, site_name)) {
+		log_error("Site name %s already exists.", site_name);
+		return NULL;
 	}
 
-	if (!replicator_dev_seg)
-		return 1;
+	if (!(rsite = dm_pool_zalloc(replicator->vg->vgmem,
+				     sizeof(*rsite)))) {
+		log_error("Allocation of replicator site failed.");
+		return NULL;
+	}
+
+	if (!(rsite->name = dm_pool_strdup(replicator->vg->vgmem,
+					   site_name))) {
+		log_error("Allocation of replicator site name failed.");
+		return NULL;
+	}
+
+	rsite->replicator = replicator;
+	dm_list_init(&rsite->rdevices);
+	dm_list_add(&replicator->rsites, &rsite->list);
+
+	return rsite;
+}
+
+static int _replicator_remove_site(struct replicator_site *rsite)
+{
+	struct replicator_device *rdev, *trdev;
+
+	dm_list_iterate_items_safe(rdev, trdev, &rsite->rdevices)
+		if (!_replicator_site_remove_device(rdev))
+			return_0;
+
+	dm_list_del(&rsite->list);
+
+	return 1;
+}
+
+
+void replicator_init(struct logical_volume *replicator)
+{
+	if (!lv_is_replicator(replicator)) {
+		dm_list_init(&replicator->rsites);
+		lv_set_hidden(replicator);
+		replicator->status |= REPLICATOR;
+	}
+}
+
+/**
+ * Connects replicator_dev segment to replicator.
+ *
+ * \param replicator
+ * \param replicator_dev_seg
+ */
+int replicator_add_replicator_dev(struct logical_volume *replicator,
+				  struct lv_segment *replicator_dev_seg)
+{
+	replicator_init(replicator);
 
 	if (replicator_dev_seg->replicator) {
-		log_error("Replicator device %s is already part of replicator.",
-			  replicator_dev_seg->lv->name);
+		log_error(INTERNAL_ERROR "Replicator device %s is already "
+			  "part of replicator.", replicator_dev_seg->lv->name);
 		return 0;
 	}
 
-	replicator_dev_seg->replicator = replicator_lv;
+	replicator_dev_seg->replicator = replicator;
+	replicator_dev_seg->rlog_lv = NULL;
+	replicator_dev_seg->lv->status |= REPLICATOR;
+
+	if (!add_seg_to_segs_using_this_lv(replicator, replicator_dev_seg))
+		return_0;
 
-	return add_seg_to_segs_using_this_lv(replicator_lv, replicator_dev_seg);
+	return 1;
 }
 
 /**
- * Returns rimage ?? lv upon succeful detach of device
- * entire LV entry should be removed by this crootall ??
+ * Returns rimage LV upon succeful detach of device
+ * entire LV entry should be removed by this call ??
  */
-struct logical_volume *replicator_remove_replicator_dev(struct lv_segment *replicator_dev_seg)
+static int _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;
+	struct replicator_site *rsite;
+	struct replicator_device *rdev;
+	struct logical_volume *replicator = replicator_dev_seg->replicator;
+	uint64_t device_index = replicator_dev_seg->lv->rdevice->device_index;
 
-	/* if slog or rimage - exit */
+	dm_list_iterate_items(rsite, &replicator->rsites) {
+		dm_list_iterate_items(rdev, &rsite->rdevices) {
+			if (rdev->device_index != device_index)
+				continue;
+			if (!_replicator_site_remove_device(rdev))
+				return_0;
+			/* no need for iterate_items_safe - 1 device per site */
+			break;
+		}
+	}
 
-	if (!remove_seg_from_segs_using_this_lv(lv, replicator_seg))
-		return_NULL;
+	if (!remove_seg_from_segs_using_this_lv(replicator, replicator_dev_seg))
+		return_0;
 
-	replicator_seg->rlog_lv = NULL;
-	lv->status &= ~REPLICATOR_LOG;
-	lv_set_visible(lv);
-#endif
+	replicator_dev_seg->lv->status &= ~REPLICATOR;
+	replicator_dev_seg->rlog_lv = NULL;
+	replicator_dev_seg->replicator = NULL;
 
-	return lv;
+	return 1;
 }
 
-int replicator_add_rlog(struct lv_segment *replicator_seg,
-			struct logical_volume *rlog_lv)
+/*
+ * Create new layered LV over the original LV
+ * this target will have a 'replicator-dev' segment
+ */
+int lv_add_replicator_dev(struct logical_volume *replicator,
+			  struct logical_volume *lv)
 {
-	if (!rlog_lv)
+	const struct segment_type *segtype;
+	struct logical_volume *rimage;
+	struct logical_volume *slog;
+	struct lv_segment *seg;
+	struct replicator_site *rsite;
+	const char *slog_name;
+	uint64_t dev_idx = first_seg(replicator)->rdevice_index_highest;
+
+	if (!(segtype = get_segtype_from_string(lv->vg->cmd, "replicator-dev")))
 		return_0;
 
-	if (rlog_lv->status & REPLICATOR_LOG) {
-		log_error("Rlog device %s is already used.", rlog_lv->name);
+	if (activation() && segtype->ops->target_present &&
+	    !segtype->ops->target_present(lv->vg->cmd, NULL, NULL)) {
+		log_error("%s: Required device-mapper target(s) not "
+			  "detected in your kernel", segtype->name);
 		return 0;
 	}
 
-	lv_set_hidden(rlog_lv);
-	rlog_lv->status |= REPLICATOR_LOG;
-	replicator_seg->rlog_lv = rlog_lv;
+	/* If replicator does not have any site defined, add local default site */
+	if (dm_list_empty(&replicator->rsites)) {
+		if (!replicator_add_site(replicator, DEFAULT_REPLICATOR_LOCAL_SITE_NAME))
+			return_0;
+		first_seg(replicator)->rsite_index_highest++;
+	}
+
+	first_seg(replicator)->rdevice_index_highest++;
+	dm_list_iterate_items(rsite, &replicator->rsites) {
+		if (rsite->site_index == 0) {
+			if (!(rimage = insert_layer_for_lv(lv->vg->cmd, lv, 0, "_rimage")))
+				return_0;
 
-	return add_seg_to_segs_using_this_lv(rlog_lv, replicator_seg);
+			seg = first_seg(lv);
+			seg->segtype = segtype; /* switch to replicator-dev */
+
+			if (!replicator_add_replicator_dev(replicator, seg))
+				return_0;
+
+			if (!replicator_site_add_device(rsite, seg, rimage->name,
+							rimage, 0, NULL, dev_idx))
+				return_0;
+		} else {
+			// FIXME: corelog support missing
+			slog_name = _replicator_device_slog_name(replicator, rsite->site_index,
+								 dev_idx);
+			if (!(slog = find_lv(lv->vg, slog_name))) {
+				log_error("Cannot find slog LV %s for %s/%s",
+					  slog_name, rsite->name, lv->name);
+				return 0;
+			}
+
+			if (!replicator_site_add_device(rsite, seg, lv->name,
+							NULL, 0, slog, dev_idx))
+				return_0;
+		}
+	}
+
+	return 1;
 }
 
-struct logical_volume *replicator_remove_rlog(struct lv_segment *replicator_seg)
+int lv_remove_replicator_dev(struct logical_volume *lv)
+{
+	/* FIXME: collect all removed devices */
+	if (!_replicator_remove_replicator_dev(first_seg(lv)))
+		return_0;
+
+	return 1;
+}
+
+int lv_add_replicator_site(struct logical_volume *replicator,
+			   const struct replicator_site *rsite)
 {
-	struct logical_volume *lv;
+	struct replicator_site *nrsite;
+
+	if (!lv_is_replicator(replicator)) {
+		log_error(INTERNAL_ERROR "Logical volume %s is not a "
+			  "replicator.", replicator->name);
+		return 0;
+	}
 
-	if (!replicator_seg)
+	if (!(nrsite = replicator_add_site(replicator, rsite->name)))
 		return_0;
 
-	if (!(lv = replicator_seg->rlog_lv)) {
-		log_error("Replog segment %s does not have rlog.",
-			  replicator_seg->lv->name);
-		return NULL;
+	if (rsite->vg_name &&
+	    !(nrsite->vg_name = dm_pool_strdup(replicator->vg->vgmem,
+					       rsite->vg_name))) {
+		log_error("Allocation of replicator site vg_name failed.");
+		return 0;
 	}
 
-	if (!remove_seg_from_segs_using_this_lv(lv, replicator_seg))
-		return_NULL;
+	nrsite->site_index = first_seg(replicator)->rsite_index_highest++;
+	nrsite->op_mode = rsite->op_mode;
+	nrsite->fall_behind_data = rsite->fall_behind_data;
+	nrsite->fall_behind_ios = rsite->fall_behind_ios;
+	nrsite->fall_behind_timeout = rsite->fall_behind_timeout;
 
-	replicator_seg->rlog_lv = NULL;
-	lv->status &= ~REPLICATOR_LOG;
-	lv_set_visible(lv);
+	return 1;
+}
 
-	return lv;
+int lv_remove_replicator_site(struct logical_volume *replicator,
+			      const char *site_name)
+{
+	struct replicator_site *rsite, *trsite;
+
+	if (!(rsite = find_site_in_replicator(replicator, site_name))) {
+		log_error(INTERNAL_ERROR "Replicator %s does not contain "
+			  "site %s.", site_name, replicator->name);
+		return 0;
+	}
+
+	if (!_replicator_remove_site(rsite))
+		return_0;
+
+	/* When the local site is removed, all remote sites must be removed */
+	if (rsite->site_index == 0) {
+		dm_list_iterate_items_safe(rsite, trsite, &replicator->rsites)
+			if (!_replicator_remove_site(rsite))
+				return_0;
+	}
+
+	return 1;
 }
 
+int vg_prearrange_replicator(struct volume_group *vg,
+			     const struct lvcreate_params *lp)
+{
+	struct logical_volume *replicator = NULL;
+	struct replicator_device *rdev;
+	struct replicator_site *rsite;
+	unsigned site_index;
+	uint64_t device_index;
 
-#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)
+	if (lp->replicator_dev || lp->rsite.name)
+		if (!(replicator = find_lv(vg, lp->replicator))) {
+			log_error("Replicator %s not found.", lp->replicator);
+			return 0;
+		}
+
+	if (lp->replicator_dev) {
+		device_index = first_seg(replicator)->rdevice_index_highest;
+		dm_list_iterate_items(rsite, &replicator->rsites) {
+			if (rsite->site_index != 0 &&
+			    !lv_add_sync_log(replicator,
+					     rsite->site_index,
+					     device_index,
+					     lp->pvh, lp->alloc))
+				return_0;
+		}
+	}
+
+	if (lp->rsite.name) {
+		site_index = first_seg(replicator)->rsite_index_highest;
+		dm_list_iterate_items(rsite, &replicator->rsites) {
+			if (rsite->site_index != 0)
+				continue;
+
+			dm_list_iterate_items(rdev, &rsite->rdevices) {
+				if (!lv_add_sync_log(replicator,
+						     site_index,
+						     rdev->device_index,
+						     lp->pvh, lp->alloc))
+					return_0;
+			}
+		}
+
+		if (!lv_add_replicator_site(replicator, &lp->rsite))
+			return_0;
+
+		if (!archive(vg))
+			return_0;
+
+		/* store vg on disk(s) */
+		if (!vg_write(vg) || !vg_commit(vg))
+			return_0;
+
+		backup(vg);
+	}
+
+	return 1;
+}
+
+int vg_add_replicator(struct logical_volume *replicator,
+		      const char *rlog_type,
+		      uint32_t region_size)
 {
-	struct logical_volume *rep_lv;
-	char *name;
-	size_t slen;
+	const struct segment_type *segtype;
+	//float sync_percent;
+	//percent_range_t percent_range;
+	struct logical_volume *rlog_lv;
+	struct lv_segment *repseg;
+	struct lvinfo info;
+
+	/*
+	 * We are unable to convert the log of inactive cluster replictors
+	 */
+	if (vg_is_clustered(replicator->vg)
+	    && !(lv_info(replicator->vg->cmd, replicator, &info, 0, 0) &&
+		 info.exists)) {
+		log_error("Replicator in this VG is not supported.");
+		return 0;
+	}
 
-	if (!(name = strstr(origin->name, rep_suffix))) {
-		log_error("Failed to find replicator suffix %s in LV name %s",
-			  rep_suffix, origin->name);
+	if (!(segtype = get_segtype_from_string(replicator->vg->cmd,
+						"replicator")))
+		return_0;
+
+	if (activation() && segtype->ops->target_present &&
+	    !segtype->ops->target_present(replicator->vg->cmd, NULL, NULL)) {
+		log_error("%s: Required device-mapper target(s) not "
+			  "detected in your kernel", segtype->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 (!(rlog_lv = insert_layer_for_lv(replicator->vg->cmd,
+					    replicator, 0, "_rlog"))) {
+		log_error("Failed to insert replicator _rlog");
+		return 0;
 	}
 
-	if (!(rep_lv = lv_create_empty(name, &origin->lvid,
-				       LVM_READ | LVM_WRITE | VISIBLE_LV,
-				       ALLOC_INHERIT, origin->vg)))
-		return_0;
+	repseg = first_seg(replicator);
+	repseg->segtype = segtype;
+
+	repseg->rlog_type = rlog_type; //"ringbuffer";
+	repseg->rdevice_index_highest = 0;
+	repseg->rsite_index_highest = 0;
+	repseg->region_size = region_size;
 
-	if (!lv_add_virtual_segment(rep_lv, 0, origin->le_count,
-				    get_segtype_from_string(origin->vg->cmd,
-							    "error")))
+	replicator_init(replicator);
+
+	if (!replicator_add_rlog(repseg, rlog_lv))
 		return_0;
 
-	rep_lv->status |= VIRTUAL;
 	return 1;
 }
 
-int lv_remove_replicator(struct logical_volume *lv)
+int vg_remove_replicator(struct logical_volume *replicator)
 {
+	/* FIXME: replace heads with error targets first */
+	if (!suspend_lv(replicator->vg->cmd, replicator)) {
+		log_error("Failed to suspend %s.",
+			  replicator->name);
+		return 0;
+	}
+
 	return 1;
 }
-#endif
 
 /*
  * Check all replicator structures:
@@ -266,7 +763,7 @@ int check_replicator_segment(const struct lv_segment *rseg)
 {
 	struct replicator_site *rsite, *rsiteb;
 	struct replicator_device *rdev, *rdevb;
-        struct logical_volume *lv = rseg->lv;
+	struct logical_volume *lv = rseg->lv;
 	int r = 1;
 
 	if (vg_is_clustered(lv->vg)) {
@@ -304,29 +801,30 @@ int check_replicator_segment(const struct lv_segment *rseg)
 			}
 		} else {
 			if (rsite->fall_behind_timeout && rsite->fall_behind_ios) {
-				log_error("Defined fall_behind_timeout and"
-					  " fall_behind_ios for async replicator %s/%s.",
+				log_error("Defined fall_behind_timeout and "
+					  "fall_behind_ios for async replicator %s/%s.",
 					  lv->name, rsite->name);
 				r = 0;
 			}
 			if (rsite->fall_behind_timeout && rsite->fall_behind_data) {
-				log_error("Defined fall_behind_timeout and"
-					  " fall_behind_data for async replicator %s/%s.",
+				log_error("Defined fall_behind_timeout and "
+					  "fall_behind_data for async replicator %s/%s.",
 					  lv->name, rsite->name);
 				r = 0;
 			}
 			if (rsite->fall_behind_ios && rsite->fall_behind_data) {
-				log_error("Defined fall_behind_ios and"
-					  " fall_behind_data for async replicator %s/%s.",
+				log_error("Defined fall_behind_ios and "
+					  "fall_behind_data for async replicator %s/%s.",
 					  lv->name, rsite->name);
 				r = 0;
 			}
 			if (!rsite->fall_behind_ios &&
 			    !rsite->fall_behind_data &&
 			    !rsite->fall_behind_timeout) {
-				log_error("fall_behind_timeout,"
-					  " fall_behind_ios and fall_behind_data are"
-					  " undefined for async replicator %s/%s.",
+				log_error("For async replicator %s/%s on of "
+					  "fall_behind_timeout, "
+					  "fall_behind_ios and fall_behind_data are "
+					  "needs to be defined.",
 					  lv->name, rsite->name);
 				r = 0;
 			}
@@ -335,16 +833,16 @@ int check_replicator_segment(const struct lv_segment *rseg)
 			if (rsite == rsiteb)
 				break;
 			if (strcasecmp(rsite->name, rsiteb->name) == 0) {
-				log_error("Duplicate site name "
-					  "%s detected for replicator %s.",
+				log_error("Duplicate site name %s "
+					  "detected for replicator %s.",
 					  rsite->name, lv->name);
 				r = 0;
 			}
 			if ((rsite->vg_name && rsiteb->vg_name &&
 			     strcasecmp(rsite->vg_name, rsiteb->vg_name) == 0) ||
 			    (!rsite->vg_name && !rsiteb->vg_name)) {
-				log_error("Duplicate VG name "
-					  "%s detected for replicator %s.",
+				log_error("Duplicate VG name %s "
+					  "detected for replicator %s.",
 					  (rsite->vg_name) ? rsite->vg_name : "<local>",
 					  lv->name);
 				r = 0;
@@ -356,8 +854,8 @@ int check_replicator_segment(const struct lv_segment *rseg)
 					  rsite->name);
 				r = 0;
 			}
-			if (rsite->site_index > rseg->rsite_index_highest) {
-				log_error("Site index %d > %d (too high) "
+			if (rsite->site_index >= rseg->rsite_index_highest) {
+				log_error("Site index %d >= %d (too high) "
 					  "for replicator site %s/%s.",
 					  rsite->site_index,
 					  rseg->rsite_index_highest,
@@ -367,6 +865,20 @@ int check_replicator_segment(const struct lv_segment *rseg)
 		}
 
 		dm_list_iterate_items(rdev, &rsite->rdevices) {
+			if (rdev->rsite->site_index == 0) {
+				if (strcasecmp(rdev->name,
+					       rdev->replicator_dev->lv->name) == 0) {
+					log_error("Self referenced device name "
+						  "%s detected for replicator %s.",
+						  rdev->name, lv->name);
+					r = 0;
+				}
+			} else if (!rdev->slog && !rdev->slog_core) {
+				log_error("Undefined slog for %s/%s "
+					  " for replicator %s.",
+					  rdev->rsite->name, rdev->name, lv->name);
+				r = 0;
+			}
 			dm_list_iterate_items(rdevb, &rsite->rdevices) {
 				if (rdev == rdevb)
 					break;
@@ -376,6 +888,13 @@ int check_replicator_segment(const struct lv_segment *rseg)
 						  rdev->slog->name, lv->name);
 					r = 0;
 				}
+				if (strcasecmp(rdev->name,
+					       rdevb->replicator_dev->lv->name) == 0) {
+					log_error("Internal self reference device "
+						  "name %s detected for replicator %s.",
+						  rdev->name, lv->name);
+					r = 0;
+				}
 				if (strcasecmp(rdev->name, rdevb->name) == 0) {
 					log_error("Duplicate device name %s "
 						  "detected for replicator %s.",
@@ -390,9 +909,9 @@ int check_replicator_segment(const struct lv_segment *rseg)
 						  lv->name, rsite->name);
 					r = 0;
 				}
-				if (rdev->device_index > rseg->rdevice_index_highest) {
-					log_error("Device index %" PRIu64
-						  " > %" PRIu64 " (too high) "
+				if (rdev->device_index >= rseg->rdevice_index_highest) {
+					log_error("Device index %" PRIu64 " >= %"
+						  PRIu64 " (too high) "
 						  "for replicator site %s/%s.",
 						  rdev->device_index,
 						  rseg->rdevice_index_highest,
@@ -406,78 +925,28 @@ int check_replicator_segment(const struct lv_segment *rseg)
 	return r;
 }
 
-/**
- * Is this segment part of active replicator
- */
-int lv_is_active_replicator_dev(const struct logical_volume *lv)
+int replicator_site_set_op_mode(struct replicator_site *rsite, const char *sitemode)
 {
-	return ((lv->status & REPLICATOR) &&
-		lv->rdevice &&
-		lv->rdevice->rsite &&
-		lv->rdevice->rsite->state == REPLICATOR_STATE_ACTIVE);
-}
+	int i;
 
-/**
- * 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);
-}
+	for (i = 0; i < sizeof(dm_op_mode_table)/sizeof(dm_op_mode_table[0]); ++i)
+		if (strcasecmp(sitemode, dm_op_mode_table[i].name) == 0) {
+			rsite->op_mode = dm_op_mode_table[i].value;
+			return 1;
+		}
 
-/**
- * Is this LV sync log
- */
-int lv_is_slog(const struct logical_volume *lv)
-{
-	return (lv->rdevice && lv->rdevice->slog == lv);
+	return 0;
 }
 
-/**
- * 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)
+const char *replicator_site_get_op_mode(const struct replicator_site *rsite)
 {
-	struct replicator_device *rdev;
-	struct replicator_site *rsite;
+	int i;
 
-	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;
-		}
+	for (i = 0; i < sizeof(dm_op_mode_table)/sizeof(dm_op_mode_table[0]); ++i)
+		if (rsite->op_mode == dm_op_mode_table[i].value)
+			return dm_op_mode_table[i].name;
 
-	return NULL;
+        return NULL;
 }
 
 /**
@@ -646,13 +1115,13 @@ int lv_read_replicator_vgs(struct logical_volume *lv)
 	struct replicator_site *rsite;
 	struct volume_group *vg;
 
-	if (!lv_is_replicator_dev(lv))
+	if (!lv_is_active_replicator_dev(lv))
 		return 1;
 
 	dm_list_iterate_items(rsite, &first_seg(lv)->replicator->rsites) {
 		if (!rsite->vg_name)
 			continue;
-		vg = vg_read(lv->vg->cmd, rsite->vg_name, 0, 0); // READ_WITHOUT_LOCK
+		vg = vg_read(lv->vg->cmd, rsite->vg_name, 0, READ_WITHOUT_LOCK);
 		if (vg_read_error(vg)) {
 			log_error("Unable to read volume group %s",
 				  rsite->vg_name);
@@ -691,3 +1160,325 @@ void lv_release_replicator_vgs(struct logical_volume *lv)
 			rsite->vg = NULL;
 		}
 }
+
+static int _write_replicator_header(struct cmd_context *cmd, struct logical_volume *lv)
+{
+	return 1;
+}
+
+/*
+ * Initialize log contents
+ *
+ * log_name = "mirror log", "replicator sync log"
+ */
+static int _init_log(struct cmd_context *cmd,
+		     struct logical_volume *log_lv, int in_sync,
+		     struct dm_list *tags, int remove_on_failure,
+		     const char *log_name,
+		     int (*write_header) (struct cmd_context *cmd,
+					  struct logical_volume *lv))
+{
+	struct str_list *sl;
+	struct lvinfo info;
+	uint64_t orig_status = log_lv->status;
+	int was_active = 0;
+
+	if (!activation() && in_sync) {
+		log_error("Aborting. Unable to create in-sync %s "
+			  "while activation is disabled.", log_name);
+		return 0;
+	}
+
+	/* If the LV is active, deactivate it first. */
+	if (lv_info(cmd, log_lv, &info, 0, 0) && info.exists) {
+		(void)deactivate_lv(cmd, log_lv);
+		/*
+		 * FIXME: workaround to fail early
+		 * Ensure that log is really deactivated because deactivate_lv
+		 * on cluster do not fail if there is log_lv with different UUID.
+		 */
+		if (lv_info(cmd, log_lv, &info, 0, 0) && info.exists) {
+			log_error("Aborting. Unable to deactivate %s.",
+				  log_name);
+			goto revert_new_lv;
+		}
+		was_active = 1;
+	}
+
+	/* Temporary make it visible for set_lv() */
+	lv_set_visible(log_lv);
+
+	/* Temporary tag mirror log for activation */
+	dm_list_iterate_items(sl, tags)
+		if (!str_list_add(cmd->mem, &log_lv->tags, sl->str)) {
+			log_error("Aborting. Unable to tag %s.", log_name);
+			goto activate_lv;
+		}
+
+	/* store mirror log on disk(s) */
+	if (!vg_write(log_lv->vg) || !vg_commit(log_lv->vg))
+		goto activate_lv;
+
+	backup(log_lv->vg);
+
+	if (!activate_lv(cmd, log_lv)) {
+		log_error("Aborting. Failed to activate %s.", log_name);
+		goto revert_new_lv;
+	}
+
+	/* Remove the temporary tags */
+	dm_list_iterate_items(sl, tags)
+		if (!str_list_del(&log_lv->tags, sl->str))
+			log_error("Failed to remove tag %s from %s.",
+				  log_name, sl->str);
+
+	if (activation() && !set_lv(cmd, log_lv, log_lv->size,
+				    in_sync ? -1 : 0)) {
+		log_error("Aborting. Failed to wipe %s.", log_name);
+		goto deactivate_and_revert_new_lv;
+	}
+
+	if (activation() && !write_header(cmd, log_lv)) { /* FIXME */
+		log_error("Aborting. Failed to write %s header.", log_name);
+		goto deactivate_and_revert_new_lv;
+	}
+
+	if (!deactivate_lv(cmd, log_lv)) {
+		log_error("Aborting. Failed to deactivate %s. "
+			  "Manual intervention required.", log_name);
+		return 0;
+	}
+
+	lv_set_hidden(log_lv);
+
+	if (was_active && !activate_lv(cmd, log_lv))
+		return_0;
+
+	return 1;
+
+deactivate_and_revert_new_lv:
+	if (!deactivate_lv(cmd, log_lv)) {
+		log_error("Unable to deactivate %s LV. "
+			  "Manual intervention required.", log_name);
+		return 0;
+	}
+
+revert_new_lv:
+	log_lv->status = orig_status;
+
+	dm_list_iterate_items(sl, tags)
+		if (!str_list_del(&log_lv->tags, sl->str))
+			log_error("Failed to remove tag %s from %s.",
+				  log_name, sl->str);
+
+	if (remove_on_failure && !lv_remove(log_lv)) {
+		log_error("Manual intervention may be required to remove "
+			  "abandoned log LV before retrying.");
+		return 0;
+	}
+
+	if (!vg_write(log_lv->vg) || !vg_commit(log_lv->vg))
+		log_error("Manual intervention may be required to "
+			  "remove/restore abandoned log LV before retrying.");
+	else
+		backup(log_lv->vg);
+
+activate_lv:
+	if (was_active && !remove_on_failure && !activate_lv(cmd, log_lv))
+		return_0;
+
+	return 0;
+}
+
+#if 0
+static int _init_replicator_log(struct cmd_context *cmd,
+				struct logical_volume *log_lv, int in_sync,
+				struct dm_list *tags, int remove_on_failure)
+{
+	if (!_init_log(cmd, log_lv, in_sync, tags, remove_on_failure,
+		       "replicator log", _write_replicator_header))
+		return_0;
+
+	return 1;
+}
+#endif
+
+static int _init_replicator_sync_log(struct cmd_context *cmd,
+				     struct logical_volume *log_lv, int in_sync,
+				     struct dm_list *tags, int remove_on_failure)
+{
+	if (!_init_log(cmd, log_lv, in_sync, tags, remove_on_failure,
+		       "sync log", _write_replicator_header))
+		return_0;
+
+	return 1;
+}
+
+/* Could be shared with mirror */
+static struct logical_volume *_create_log(struct logical_volume *lv,
+					  struct alloc_handle *ah,
+					  alloc_policy_t alloc,
+					  const char *lv_name,
+					  const char *suffix,
+					  uint64_t status)
+{
+	struct logical_volume *log_lv;
+	char *log_name;
+	size_t len;
+
+	len = strlen(lv_name) + 32;
+	if (!(log_name = alloca(len))) {
+		log_error("log_name allocation failed.");
+		return NULL;
+	}
+
+	if (dm_snprintf(log_name, len, "%s%s", lv_name, suffix) < 0) {
+		log_error("log_name allocation failed.");
+		return NULL;
+	}
+
+	if (!(log_lv = lv_create_empty(log_name, NULL,
+				       VISIBLE_LV | LVM_READ | LVM_WRITE,
+				       alloc, lv->vg)))
+		return_NULL;
+
+	if (!lv_add_log_segment(ah, 0, log_lv, status))
+		return_NULL;
+
+	return log_lv;
+}
+
+#if 0
+static struct logical_volume *_set_up_replicator_log(struct cmd_context *cmd,
+						     struct alloc_handle *ah,
+						     struct logical_volume *lv,
+						     uint32_t log_size __attribute((unused)),
+						     alloc_policy_t alloc,
+						     int in_sync)
+{
+	struct logical_volume *log_lv;
+	const char *suffix, *c;
+	char *lv_name;
+	size_t len;
+	struct lv_segment *seg;
+
+	//init_mirror_in_sync(in_sync);
+
+	/* Replicator log name is lv_name + suffix, determined as the following:
+	 *   1. suffix is:
+	 *        o "_rlog" for the original replicator LV.
+	 *        o "_rlogtmp_%d" for temporary mirror LV,
+	 *   2. lv_name is:
+	 *        o lv->name, if the log is temporary
+	 *        o otherwise, the top-level LV name
+	 */
+	seg = first_seg(lv);
+	if (seg_type(seg, 0) == AREA_LV &&
+	    strstr(seg_lv(seg, 0)->name, MIRROR_SYNC_LAYER)) {
+		lv_name = lv->name;
+		suffix = "_rlogtmp_%d";
+	} else if ((c = strstr(lv->name, MIRROR_SYNC_LAYER))) {
+		len = (size_t)(c - lv->name + 1);
+		if (!(lv_name = alloca(len)) ||
+		    !dm_snprintf(lv_name, len, "%s", lv->name)) {
+			log_error("replicator log name allocation failed");
+			return 0;
+		}
+		suffix = "_rlog";
+	} else {
+		lv_name = lv->name;
+		suffix = "_rlog";
+	}
+
+	if (!(log_lv = _create_log(lv, ah, alloc, lv_name, suffix, REPLICATOR_LOG))) {
+		log_error("Failed to create replicator log.");
+		return NULL;
+	}
+
+	if (!_init_replicator_log(cmd, log_lv, in_sync, &lv->tags, 1)) {
+		log_error("Failed to initialise replicator log.");
+		return NULL;
+	}
+
+	return log_lv;
+}
+#endif
+
+static struct logical_volume *_set_up_sync_log(struct cmd_context *cmd,
+					       struct alloc_handle *ah,
+					       struct logical_volume *replicator,
+                                               unsigned site_index,
+					       uint64_t device_index,
+					       alloc_policy_t alloc,
+					       int in_sync)
+{
+	struct logical_volume *log_lv;
+	const char *suffix = "";
+	char *lv_name;
+
+	if (!(lv_name = _replicator_device_slog_name(replicator, site_index, device_index)))
+		return_NULL;
+
+	if (!(log_lv = _create_log(replicator, ah, alloc, lv_name, suffix,
+				   REPLICATOR_LOG))) {
+		log_error("Failed to create replicator sync log.");
+		return NULL;
+	}
+
+	if (!_init_replicator_sync_log(cmd, log_lv, in_sync, &replicator->tags, 1)) {
+		log_error("Failed to initialise replicator sync log.");
+		return NULL;
+	}
+
+	return log_lv;
+}
+
+int lv_add_sync_log(struct logical_volume *replicator,
+		    unsigned site_index,
+		    uint64_t device_index,
+		    struct dm_list *allocatable_pvs,
+		    alloc_policy_t alloc)
+{
+	struct cmd_context *cmd = replicator->vg->cmd;
+	const struct segment_type *segtype;
+	struct alloc_handle *ah;
+	uint32_t region_size;
+	int in_sync;
+	int r = 1;
+
+	if (!(segtype = get_segtype_from_string(cmd, "striped")))
+		return_0;
+
+	if (activation() && segtype->ops->target_present &&
+	    !segtype->ops->target_present(cmd, NULL, NULL)) {
+		log_error("%s: Required device-mapper target(s) not "
+			  "detected in your kernel", segtype->name);
+		return 0;
+	}
+
+	region_size = adjusted_mirror_region_size(replicator->vg->extent_size,
+						  replicator->le_count,
+						  first_seg(replicator)->region_size);
+
+	/* allocate destination extents */
+	ah = allocate_extents(replicator->vg, NULL, segtype,
+			      0, 0, 1, region_size, 0,
+			      allocatable_pvs, alloc, NULL);
+	if (!ah) {
+		log_error("Unable to allocate extents for replicator sync log.");
+		return 0;
+	}
+
+	/* check sync status */
+	in_sync = 0;
+
+	if (!_set_up_sync_log(cmd, ah, replicator, site_index, device_index,
+			      alloc, in_sync)) {
+		stack;
+		r = 0;
+	}
+
+	alloc_destroy(ah);
+
+	return r;
+}
Signature · 1 line
1.7.1.1
#13 lore raw

PATCH 13/22 Replicator: replicator.c changes

In reply to Zdenek Kabelac

Changes for replicator.c source file.

Reusing few new API functions from replicator_manip.c for replicator. Add few missing log_error() diagnostic messages instead of <backtrace>.

Segment for replicator has now SEG_VIRTUAL and SEG_CANNOT_BE_ZEROED flags. (Not really sure about logic here).

---
 lib/replicator/replicator.c |  178 +++++++++++++++----------------------------
 1 files changed, 61 insertions(+), 117 deletions(-)
lib/replicator/replicator.c +61 -117
index 6f09321..821e16d 100644
@@ -104,61 +104,17 @@ static replicator_state_t _get_state(const struct config_node *sn,
 	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;
+	if ((rsite = find_site_in_replicator(replicator, key)))
+		return rsite;
 
-	rsite->replicator = replicator;
-	dm_list_init(&rsite->rdevices);
-	dm_list_add(&replicator->rsites, &rsite->list);
-
-	return rsite;
+	return replicator_add_site(replicator, key);
 }
 
-
 /* Parse replicator site element */
 static int _add_site(struct lv_segment *seg,
 		     const char *key,
@@ -167,6 +123,7 @@ static int _add_site(struct lv_segment *seg,
 	struct dm_pool *mem = seg->lv->vg->vgmem;
 	const struct config_node *cn;
 	struct replicator_site *rsite;
+	char *op_mode;
 
 	if (!(rsite = _get_site(seg->lv, key)))
 		return_0;
@@ -200,8 +157,11 @@ static int _add_site(struct lv_segment *seg,
 			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 (!get_config_str(sn, "operation_mode", &op_mode))
+			return SEG_LOG_ERROR("Operation mode undefined in");
+
+		if (!replicator_site_set_op_mode(rsite, op_mode))
+			return SEG_LOG_ERROR("Unknown value for operation mode in");
 	}
 
 	if ((cn = find_config_node(sn, "volume_group"))) {
@@ -226,8 +186,7 @@ static int _replicator_text_import(struct lv_segment *seg,
 	const struct config_node *cn;
 	struct logical_volume *rlog_lv;
 
-	if (!replicator_add_replicator_dev(seg->lv, NULL))
-		return_0;
+	replicator_init(seg->lv);
 
 	if (!(cn = find_config_node(sn, "replicator_log")) ||
 	    !cn->v || cn->v->type != CFG_STRING)
@@ -246,7 +205,6 @@ static int _replicator_text_import(struct lv_segment *seg,
 	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);
 
@@ -267,6 +225,7 @@ static int _replicator_text_import(struct lv_segment *seg,
 			if (!_add_site(seg, sn->key, sn->child))
 				return_0;
 		}
+
 	return 1;
 }
 
@@ -275,9 +234,10 @@ static int _replicator_text_export(const struct lv_segment *seg,
 				   struct formatter *f)
 {
 	struct replicator_site *rsite;
+	const char *op_mode;
 
 	if (!seg->rlog_lv)
-                return_0;
+		return_0;
 
 	outf(f, "replicator_log = \"%s\"", seg->rlog_lv->name);
 	outf(f, "replicator_log_type = \"%s\"", seg->rlog_type);
@@ -299,9 +259,13 @@ static int _replicator_text_export(const struct lv_segment *seg,
 		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->op_mode != DM_REPLICATOR_SYNC) {
+			if (!(op_mode = replicator_site_get_op_mode(rsite))) {
+				log_error("Unknown operation mode.");
+				return 0;
+			}
+			outf(f, "operation_mode = \"%s\"", op_mode);
+		}
 		if (rsite->fall_behind_timeout)
 			outfc(f, "# seconds", "fall_behind_timeout = %u",
 			     rsite->fall_behind_timeout);
@@ -445,13 +409,13 @@ static int _add_device(struct lv_segment *seg,
 		       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 logical_volume *rimage = NULL;
+	struct logical_volume *slog = NULL;
 	struct replicator_site *rsite = _get_site(seg->replicator, site_name);
 	struct replicator_device *rdev;
-	const char *dev_str = NULL;
+	const char *lv_name = NULL;
 	const char *slog_str = NULL;
+	uint32_t slog_core = 0;
 	const struct config_node *cn;
 
 	dm_list_iterate_items(rdev, &rsite->rdevices)
@@ -459,61 +423,42 @@ static int _add_device(struct lv_segment *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->v && cn->v->v.str)
+			slog_str = cn->v->v.str;
+		else if (!get_config_uint32(sn, "sync_log", &slog_core))
+			return SEG_LOG_ERROR("Could not read 'sync_log' for");
 	}
 
 	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;
+	lv_name = 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);
+					     "site device in", slog_str);
 
 		/* Check for device in current VG */
-		if (!(lv = find_lv(seg->lv->vg, dev_str)))
+		if (!(rimage = find_lv(seg->lv->vg, lv_name)))
 			return SEG_LOG_ERROR("Logical volume %s not found in",
-					     dev_str);
+					     lv_name);
 	} else {
-		if (!slog_str)
+		if (!slog_str && !slog_core)
 			return SEG_LOG_ERROR("Sync log is missing for remote "
-					     "device in");
+					     "site device in");
 		/* Check for slog device in current VG */
-		if (!(slog_lv = find_lv(seg->lv->vg, slog_str)))
+		if (!slog_core &&
+		    !(slog = 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)))
+	if (!replicator_site_add_device(rsite, seg, lv_name, rimage,
+					slog_core, slog, devidx))
 		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;
 }
 
@@ -553,9 +498,6 @@ static int _replicator_dev_text_import(struct lv_segment *seg,
 	if (!seg->lv->rdevice)
 		return SEG_LOG_ERROR("Replicator device without site in");
 
-	seg->rlog_lv = NULL;
-	seg->lv->status |= REPLICATOR;
-
 	return 1;
 }
 
@@ -586,10 +528,12 @@ static int _replicator_dev_text_export(const struct lv_segment *seg,
 			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);
+			if (rsite->site_index != 0) {
+				if (rdev->slog)
+					outf(f, "sync_log = \"%s\"", rdev->slog->name);
+				else
+					outf(f, "sync_log = %d", rdev->slog_core);
+			}
 
 			out_dec_indent(f);
 
@@ -625,8 +569,10 @@ static int _replicator_dev_add_target_line(struct dev_manager *dm,
 				 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;
+		if (!(rdev_dlid = build_dm_uuid(mem, seg->lv->rdevice->lv->lvid.s, NULL))) {
+			log_error("Failed to build replicator-dev uuid.");
+			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)",
@@ -640,8 +586,10 @@ static int _replicator_dev_add_target_line(struct dev_manager *dm,
 	 * 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;
+	    !(replicator_dlid = build_dm_uuid(mem, seg->replicator->lvid.s, NULL))) {
+		log_error("Failed to build replicator dlid.");
+		return 0;
+	}
 
 	/* Select remote devices with the same device index */
 	dm_list_iterate_items(rsite, &seg->replicator->rsites) {
@@ -664,8 +612,10 @@ static int _replicator_dev_add_target_line(struct dev_manager *dm,
 		}
 
 		if (!rdev->lv ||
-		    !(rdev_dlid = build_dm_uuid(mem, rdev->lv->lvid.s, NULL)))
-			return_0;
+		    !(rdev_dlid = build_dm_uuid(mem, rdev->lv->lvid.s, NULL))) {
+			log_error("Failed UUID allocation.");
+			return 0;
+		}
 
 		slog_dlid = NULL;
 
@@ -675,18 +625,12 @@ static int _replicator_dev_add_target_line(struct dev_manager *dm,
 			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  {
+		} else if (rdev->slog_core || (rsite->site_index == 0)) {
 			slog_flags = DM_CORELOG | DM_FORCESYNC;
 			slog_size = 0; /* NOLOG */
+		} else {
+			log_error(INTERNAL_ERROR "Either slog or corelog must be used.");
+			return 0;
 		}
 
 		if (!dm_tree_node_add_replicator_dev_target(node,
@@ -766,7 +710,7 @@ int init_multiple_segtype(struct segtype_library *seglib)
 	segtype->ops = &_replicator_ops;
 	segtype->name = REPLICATOR_MODULE;
 	segtype->private = NULL;
-	segtype->flags = SEG_REPLICATOR;
+	segtype->flags = SEG_REPLICATOR | SEG_VIRTUAL | SEG_CANNOT_BE_ZEROED;
 
 	if (!lvm_register_segtype(seglib, segtype))
 		return_0;
Signature · 1 line
1.7.1.1
#14 lore raw

PATCH 14/22 Replicator: add new command option read functions

In reply to Zdenek Kabelac

site_arg - reads name of the site.
sitemode_arg - reads site mode.

---
 tools/lvmcmdline.c |   24 ++++++++++++++++++++++++
 tools/tools.h      |    2 ++
 2 files changed, 26 insertions(+), 0 deletions(-)
tools/lvmcmdline.c +24 -0
index 8ff74ac..7d55e48 100644
@@ -473,6 +473,30 @@ int readahead_arg(struct cmd_context *cmd __attribute((unused)), struct arg *a)
 	return 1;
 }
 
+int site_arg(struct cmd_context *cmd __attribute((unused)), struct arg *a)
+{
+	if (!validate_name(a->value)) {
+		log_error("Invalid site name.");
+		return 0;
+	}
+
+	return 1;
+}
+
+int sitemode_arg(struct cmd_context *cmd __attribute((unused)), struct arg *a)
+{
+	struct replicator_site rsite;
+
+	if (!replicator_site_set_op_mode(&rsite, a->value)) {
+		log_error("Invalid site mode %s.", a->value);
+		return 0;
+	}
+
+	a->ui_value = rsite.op_mode;
+
+	return 1;
+}
+
 /*
  * Non-zero, positive integer, "all", or "unmanaged"
  */
tools/tools.h +2 -0
index 2e06fc2..3104d0a 100644
@@ -153,6 +153,8 @@ int segtype_arg(struct cmd_context *cmd, struct arg *a);
 int alloc_arg(struct cmd_context *cmd, struct arg *a);
 int readahead_arg(struct cmd_context *cmd, struct arg *a);
 int metadatacopies_arg(struct cmd_context *cmd __attribute((unused)), struct arg *a);
+int site_arg(struct cmd_context *cmd, struct arg *a);
+int sitemode_arg(struct cmd_context *cmd, struct arg *a);
 
 /* we use the enums to access the switches */
 unsigned arg_count(const struct cmd_context *cmd, int a);
Signature · 1 line
1.7.1.1
#15 lore raw

PATCH 15/22 Replicator: new args

In reply to Zdenek Kabelac
---
 tools/args.h |   10 ++++++++++
 1 files changed, 10 insertions(+), 0 deletions(-)
tools/args.h +10 -0
index a23c46c..78f2177 100644
@@ -69,6 +69,16 @@ arg(noudevsync_ARG, '\0', "noudevsync", NULL, 0)
 arg(poll_ARG, '\0', "poll", yes_no_arg, 0)
 arg(stripes_long_ARG, '\0', "stripes", int_arg, 0)
 arg(sysinit_ARG, '\0', "sysinit", NULL, 0)
+arg(replicator_ARG, '\0', "replicator", string_arg, 0)
+arg(replicatordev_ARG, '\0', "replicatordev", NULL, 0)
+arg(replicatorsynclog_ARG, '\0', "replicatorsynclog", string_arg, 0)
+arg(replicatorlogtype_ARG, '\0', "replicatorlogtype", string_arg, 0)
+arg(site_ARG, '\0', "site", site_arg, 0)
+arg(fallbehinddata_ARG, '\0', "fallbehinddata", size_mb_arg, 0)
+arg(fallbehindios_ARG, '\0', "fallbehindios", int_arg, 0)
+arg(fallbehindtimeout_ARG, '\0', "fallbehindtimeout", int_arg, 0)
+arg(sitemode_ARG, '\0', "sitemode", sitemode_arg, 0)
+arg(remotevg_ARG, '\0', "remotevg", string_arg, 0)
 
 /* Allow some variations */
 arg(resizable_ARG, '\0', "resizable", yes_no_arg, 0)
Signature · 1 line
1.7.1.1
#16 lore raw

PATCH 16/22 Replicator: read site_params

In reply to Zdenek Kabelac

Common function for parsing replicator site parameters. It's used by lvcreate and lvchange command in later patch.

---
 tools/toollib.c |  111 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 tools/toollib.h |    3 +
 2 files changed, 114 insertions(+), 0 deletions(-)
tools/toollib.c +111 -0
index bdb52d5..f1da944 100644
@@ -1551,3 +1551,114 @@ int get_stripe_params(struct cmd_context *cmd, uint32_t *stripes, uint32_t *stri
 	return _validate_stripe_params(cmd, stripes, stripe_size);
 }
 
+/**
+ * Parse parameters for replicator site
+ *
+ * \param cmd
+ * \param rsite
+ * \param changed
+ */
+int get_replicator_site_params(struct cmd_context *cmd,
+			       struct replicator_site *rsite,
+			       int *changed)
+{
+	struct replicator_site nrsite;
+
+	if (arg_count(cmd, fallbehinddata_ARG)) {
+		nrsite.fall_behind_data =
+			arg_uint64_value(cmd, fallbehinddata_ARG,
+					 DEFAULT_REPLICATOR_FALL_BEHIND_DATA);
+		if (rsite->fall_behind_data != nrsite.fall_behind_data) {
+			rsite->fall_behind_data = nrsite.fall_behind_data;
+			rsite->fall_behind_ios = 0;
+			rsite->fall_behind_timeout = 0;
+			(*changed)++;
+		}
+	}
+
+	if (arg_count(cmd, fallbehindios_ARG)) {
+		if (arg_count(cmd, fallbehinddata_ARG)) {
+			log_error("Only one asynchronous parameter can be used.");
+			return 0;
+		}
+		nrsite.fall_behind_ios =
+			arg_uint_value(cmd, fallbehindios_ARG,
+				       DEFAULT_REPLICATOR_FALL_BEHIND_IOS);
+
+		if (rsite->fall_behind_ios != nrsite.fall_behind_ios) {
+			rsite->fall_behind_data = 0;
+			rsite->fall_behind_ios = nrsite.fall_behind_ios;
+			rsite->fall_behind_timeout = 0;
+			(*changed)++;
+		}
+	}
+
+	if (arg_count(cmd, fallbehindtimeout_ARG)) {
+		if (arg_count(cmd, fallbehinddata_ARG) ||
+		    arg_count(cmd, fallbehindios_ARG)) {
+			log_error("Only one asynchronous parameter can be used.");
+			return 0;
+		}
+		nrsite.fall_behind_timeout =
+			arg_uint_value(cmd, fallbehindtimeout_ARG,
+				       DEFAULT_REPLICATOR_FALL_BEHIND_TIMEOUT);
+
+		if (rsite->fall_behind_timeout != nrsite.fall_behind_timeout) {
+			rsite->fall_behind_data = 0;
+			rsite->fall_behind_ios = 0;
+			rsite->fall_behind_timeout = nrsite.fall_behind_timeout;
+			(*changed)++;
+		}
+	}
+
+	nrsite.op_mode = NUM_DM_REPLICATOR_MODES;
+	if (arg_count(cmd, sitemode_ARG)) {
+		nrsite.op_mode = arg_uint_value(cmd, sitemode_ARG,
+						DEFAULT_REPLICATOR_ASYNC_MODE);
+		if ((nrsite.op_mode == DM_REPLICATOR_SYNC) &&
+		    !arg_count(cmd, fallbehinddata_ARG) &&
+		    !arg_count(cmd, fallbehindios_ARG) &&
+		    !arg_count(cmd, fallbehindtimeout_ARG) &&
+		    (rsite->fall_behind_data ||
+		     rsite->fall_behind_ios ||
+		     rsite->fall_behind_timeout)) {
+			rsite->fall_behind_data = 0;
+			rsite->fall_behind_ios = 0;
+			rsite->fall_behind_timeout = 0;
+			(*changed)++;
+			log_debug("Clearing asynchronous parameters synchronous site.");
+		}
+	}
+
+	if (rsite->fall_behind_data ||
+	    rsite->fall_behind_ios ||
+	    rsite->fall_behind_timeout) {
+		if (!rsite->vg_name) {
+			log_error("Cannot set asynchronous parameters for "
+				  "the local site %s.", rsite->name);
+			return 0;
+		}
+		if (nrsite.op_mode == DM_REPLICATOR_SYNC) {
+			log_error("For synchronous site mode all asynchronous "
+				  "parameters must be deleted.");
+			return 0;
+		} else if (nrsite.op_mode == NUM_DM_REPLICATOR_MODES)
+			nrsite.op_mode = (rsite->op_mode == DM_REPLICATOR_SYNC) ?
+				DEFAULT_REPLICATOR_ASYNC_MODE : rsite->op_mode;
+	} else {
+		if (nrsite.op_mode != NUM_DM_REPLICATOR_MODES &&
+		    nrsite.op_mode != DM_REPLICATOR_SYNC) {
+			log_error("For asynchronous site mode an asynchronous "
+				  "non-zero parameter must be specified.");
+			return 0;
+		}
+		nrsite.op_mode = DM_REPLICATOR_SYNC;
+	}
+
+	if (rsite->op_mode != nrsite.op_mode) {
+		rsite->op_mode = nrsite.op_mode;
+		(*changed)++;
+	}
+
+	return 1;
+}
tools/toollib.h +3 -0
index daab95a..1d3d3c1 100644
@@ -118,4 +118,7 @@ int get_activation_monitoring_mode(struct cmd_context *cmd,
 int get_stripe_params(struct cmd_context *cmd, uint32_t *stripes,
 		      uint32_t *stripe_size);
 
+int get_replicator_site_params(struct cmd_context *cmd,
+			       struct replicator_site *rsite,
+			       int *changed);
 #endif
Signature · 1 line
1.7.1.1
#17 lore raw

PATCH 17/22 Replicator: lv_manip - create replicator

In reply to Zdenek Kabelac
---
 lib/metadata/lv_manip.c |  126 ++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 125 insertions(+), 1 deletions(-)
lib/metadata/lv_manip.c +125 -1
index 5e4a674..e59f264 100644
@@ -418,6 +418,8 @@ static int _lv_reduce(struct logical_volume *lv, uint32_t extents, int delete)
 			/* FIXME Check this is safe */
 			if (seg->log_lv && !lv_remove(seg->log_lv))
 				return_0;
+			if (seg->rlog_lv && !lv_remove(seg->rlog_lv))
+				return_0;
 			dm_list_del(&seg->list);
 			reduction = seg->len;
 		} else
@@ -2205,6 +2207,7 @@ int lv_remove_single(struct cmd_context *cmd, struct logical_volume *lv,
 	struct volume_group *vg;
 	struct lvinfo info;
 	struct logical_volume *origin = NULL;
+	struct logical_volume *replicator = NULL;
 	int was_merging = 0;
 
 	vg = lv->vg;
@@ -2230,6 +2233,12 @@ int lv_remove_single(struct cmd_context *cmd, struct logical_volume *lv,
 		return 0;
 	}
 
+	if (lv_is_rimage(lv) || lv_is_rlog(lv) || lv_is_slog(lv)) {
+		log_error("Can't remove logical volume %s used by a "
+			  "replicator.", lv->name);
+		return 0;
+	}
+
 	if (lv->status & LOCKED) {
 		log_error("Can't remove locked LV %s", lv->name);
 		return 0;
@@ -2267,6 +2276,14 @@ int lv_remove_single(struct cmd_context *cmd, struct logical_volume *lv,
 			return_0;
 	}
 
+	if (lv_is_replicator_dev(lv)) {
+                replicator = first_seg(lv)->replicator;
+		if (!lv_remove_replicator_dev(lv)) {
+			log_error("Unable to remove replicator-dev %s", lv->name);
+			return 0;
+		}
+	}
+
 	if (!deactivate_lv(cmd, lv)) {
 		log_error("Unable to deactivate logical volume \"%s\"",
 			  lv->name);
@@ -2295,6 +2312,17 @@ int lv_remove_single(struct cmd_context *cmd, struct logical_volume *lv,
 		}
 	}
 
+	if (replicator) {
+		if (!suspend_lv(cmd, replicator)) {
+			log_error("Failed to refresh replicator %s.", replicator->name);
+			return 0;
+		}
+		if (!resume_lv(cmd, replicator)) {
+			log_error("Failed to resume replicator %s.", replicator->name);
+			return 0;
+		}
+	}
+
 	backup(vg);
 
 	if (lv_is_visible(lv))
@@ -2310,6 +2338,8 @@ int lv_remove_with_dependencies(struct cmd_context *cmd, struct logical_volume *
 				const force_t force, unsigned level)
 {
 	struct dm_list *snh, *snht;
+	struct replicator_site *rsite;
+	struct replicator_device *rdev;
 
 	if (lv_is_cow(lv)) {
 		/* A merging snapshot cannot be removed directly */
@@ -2320,6 +2350,18 @@ int lv_remove_with_dependencies(struct cmd_context *cmd, struct logical_volume *
 		}
 	}
 
+	if (lv_is_replicator(lv)) {
+		/* Remove replicators' head LVs first */
+		dm_list_iterate_items(rsite, &lv->rsites) {
+			if (rsite->site_index != 0)
+				continue;
+			dm_list_iterate_items(rdev, &rsite->rdevices)
+				if (!lv_remove_with_dependencies(cmd, rdev->lv,
+								 force, level + 1))
+					return_0;
+		}
+	}
+
 	if (lv_is_origin(lv)) {
 		/* remove snapshot LVs first */
 		dm_list_iterate_safe(snh, snht, &lv->snapshot_segs) {
@@ -2998,6 +3040,7 @@ int lv_create_single(struct volume_group *vg,
 	struct logical_volume *lv, *org = NULL;
 	int origin_active = 0;
 	struct lvinfo info;
+	struct logical_volume *replicator;
 
 	if (lp->lv_name && find_lv_in_vg(vg, lp->lv_name)) {
 		log_error("Logical volume \"%s\" already exists in "
@@ -3118,6 +3161,13 @@ int lv_create_single(struct volume_group *vg,
 		}
 	}
 
+	if (lp->replicator) {
+		if (!vg_prearrange_replicator(vg, lp))
+			return_0;
+		if (lp->rsite.name && !lp->replicator_dev)
+			return 1; /* Do not create any LV this time */
+	}
+
 	if (!lp->extents) {
 		log_error("Unable to create new logical volume with no extents");
 		return 0;
@@ -3169,6 +3219,19 @@ int lv_create_single(struct volume_group *vg,
 		}
 	}
 
+	if (lp->replicator_dev) {
+		init_replicator_in_sync(lp->nosync);
+
+		if (lp->nosync) {
+			log_error("FIXME: Unsupported.");
+			return 0;
+
+			log_warn("WARNING: New replicator won't be synchronised. "
+				  "Don't read what you didn't write!");
+			status |= REPLICATOR_NOTSYNCED;
+		}
+	}
+
 	if (!(lv = lv_create_empty(lp->lv_name ? lp->lv_name : "lvol%d", NULL,
 				   status, lp->alloc, vg)))
 		return_0;
@@ -3225,6 +3288,12 @@ int lv_create_single(struct volume_group *vg,
 				  "exception store.");
 			goto revert_new_lv;
 		}
+	} else if (lp->replicator_dev || lp->replicator) {
+		if (!activate_lv_excl(cmd, lv)) {
+			log_error("Aborting. Failed to activate replicator "
+				  "device.");
+			goto revert_new_lv;
+		}
 	} else if (!activate_lv(cmd, lv)) {
 		if (lp->zero) {
 			log_error("Aborting. Failed to activate new LV to wipe "
@@ -3240,10 +3309,65 @@ int lv_create_single(struct volume_group *vg,
 	else if (!set_lv(cmd, lv, UINT64_C(0), 0)) {
 		log_error("Aborting. Failed to wipe %s.",
 			  lp->snapshot ? "snapshot exception store" :
-					 "start of new LV");
+			  lp->replicator ? "replicator backing store" :
+					   "start of new LV");
 		goto deactivate_and_revert_new_lv;
 	}
 
+	if (!lp->replicator_dev && lp->replicator) {
+		if (!deactivate_lv(cmd, lv)) {
+			log_error("Aborting. Couldn't deactivate replicator log."
+				  " Manual intervention required.");
+			return 0;
+		}
+		if (!vg_add_replicator(lv, lp->rlog_type, lp->region_size)) {
+			log_error("Could not create replicator.");
+			goto revert_new_lv;
+		}
+		/* store vg on disk(s) */
+		if (!vg_write(vg) || !vg_commit(vg))
+			return_0;
+	}
+
+	if (lp->replicator_dev) {
+		if (!lp->replicator) {
+			log_error("Replicator is not specified.");
+			return 0;
+		}
+		if (!deactivate_lv(cmd, lv)) {
+			log_error("Aborting. Could not deactivate new LV.");
+			return 0;
+		}
+
+		if (!(replicator = find_lv(vg, lp->replicator))) {
+			log_error("Could not find replicator.");
+			goto revert_new_lv;
+		}
+
+		if (!lv_add_replicator_dev(replicator, lv)) {
+			log_error("Could not insert replicator device to replicator.");
+			goto revert_new_lv;
+		}
+
+		/* store vg on disk(s) */
+		if (!vg_write(vg))
+			return_0;
+
+		if (!suspend_lv(cmd, replicator)) {
+			log_error("Failed to suspend replicator %s", replicator->name);
+			vg_revert(vg);
+			return 0;
+		}
+
+		if (!vg_commit(vg))
+			return_0;
+
+		if (!resume_lv(cmd, replicator)) {
+			log_error("Problem reactivating replicator %s", replicator->name);
+			return 0;
+		}
+	}
+
 	if (lp->snapshot) {
 		/* Reset permission after zeroing */
 		if (!(lp->permission & LVM_WRITE))
Signature · 1 line
1.7.1.1
#18 lore raw

PATCH 18/22 Replicator: lvcreate implementation

In reply to Zdenek Kabelac
---
 tools/commands.h |    9 ++++
 tools/lvcreate.c |  133 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 139 insertions(+), 3 deletions(-)
tools/commands.h +9 -0
index 2b34933..7966cff 100644
@@ -165,6 +165,12 @@ xx(lvcreate,
    "\t[-p|--permission {r|rw}]\n"
    "\t[-r|--readahead ReadAheadSectors|auto|none]\n"
    "\t[-R|--regionsize MirrorLogRegionSize]\n"
+   "\t[--replicator [ReplicatorName] [--replicatorlogtype ringbuffer]\n"
+   "\t[{--replicatorsynclog {disk|core}|--corelog}]\n"
+   "\t[--site LocalSiteName [--sitemode {sync|warn|stall|drop|fail}]\n"
+   "\t  [--remotevg RemoteVGName] [{--fallbehinddata Size[bBsSkKmMgG]|\n"
+   "\t    --fallbehindios IOCount|--fallbehindtimeout Secs}]]\n"
+   "\t[--replicatordev]\n"
    "\t[-t|--test]\n"
    "\t[--type VolumeType]\n"
    "\t[-v|--verbose]\n"
@@ -203,6 +209,9 @@ xx(lvcreate,
    mirrorlog_ARG, mirrors_ARG, monitor_ARG, name_ARG, nosync_ARG, noudevsync_ARG,
    permission_ARG, persistent_ARG, readahead_ARG, regionsize_ARG, size_ARG,
    snapshot_ARG, stripes_ARG, stripesize_ARG, test_ARG, type_ARG,
+   replicator_ARG, replicatordev_ARG, replicatorlogtype_ARG,
+   remotevg_ARG, site_ARG, sitemode_ARG,
+   fallbehinddata_ARG, fallbehindios_ARG, fallbehindtimeout_ARG,
    virtualoriginsize_ARG, virtualsize_ARG, zero_ARG)
 
 xx(lvdisplay,
tools/lvcreate.c +130 -3

193 lines not on this page · raw message

Signature · 1 line
1.7.1.1
#19 lore raw

PATCH 19/22 Replicator: man page update for lvcreate

In reply to Zdenek Kabelac

Update man page to cover basic usage of lvcreate

Current descriptions shows how to create replicator, add site, add replicated device.

---
 man/lvcreate.8.in |   76 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 76 insertions(+), 0 deletions(-)
man/lvcreate.8.in +76 -0
index 0d0976f..eecedf7 100644
@@ -36,6 +36,27 @@ VolumeGroupName [PhysicalVolumePath[:PE[-PE]]...]
 OriginalLogicalVolumePath | 
 [\-s|\-\-snapshot]
 VolumeGroupName \-\-virtualsize VirtualSize}
+.br
+
+.br
+.B lvcreate
+\-\-replicator [ReplicatorName[Path]]
+[\-\-replicatordev]
+{\-l|\-\-extents LogicalExtentsNumber[%{VG|FREE|ORIGIN}] |
+ \-L|\-\-size LogicalVolumeSize[bBsSkKmMgGtTpPeE]}
+[\-\-nosync]
+[\-\-replicatorlogtype ReplicatorLogType]
+{[\-\-replicatorsynclog {disk|core}] | [\-\-corelog]}
+[\-R|\-\-regionsize ReplicatorSyncLogRegionSize]]
+[\-\-site SiteName [\-\-sitemode {sync|warn|stall|drop|fail}]
+{[\-\-fallbehinddata Size[bBsSkKmMgGtTpPeE]] |
+[\-\-fallbehindios  IOS] |
+[\-\-fallbehindtimeout secs]}
+[\-\-remotevg RemoteVolumeGroupName]]
+\-n|\-\-name ReplicatorName
+VolumeGroupName
+.br
+
 .SH DESCRIPTION
 lvcreate creates a new logical volume in a volume group ( see
 .B vgcreate(8), vgchange(8)
@@ -52,6 +73,8 @@ extents will be restricted to these volumes.
 .br
 The second form supports the creation of snapshot logical volumes which 
 keep the contents of the original logical volume for backup purposes.
+.br
+The third form supports the creation of replicated devices.
 .SH OPTIONS
 See \fBlvm\fP for common options.
 .TP
@@ -120,6 +143,40 @@ device is activated, for example, after every reboot.  Using "mirrored"
 will create a persistent log that is itself mirrored.
 
 The optional argument --corelog is equivalent to --mirrorlog core.
+.TP
+.I \-\-replicator
+Creates empty replicator logical volume. (see \fBlvchange\fP(8)) for
+options, how to customize created replicator LV.
+Specifying optional argument --nosync will cause the creation
+of the replicator to skip the initial resynchronization. Any data written
+afterwards will be replicated, but the original content will not be
+copied.  This is useful for skipping a potentially long and resource
+intensive initial sync of an empty device.  Currrently this flag is not
+supported.
+
+The optional argument --replicatorsynclog specifies the type of synclog to be
+used. The default is disk, which is persistent and requires a small amount of
+storage space. Using core means the replicator is regenerated by copying the
+data from the first device again each time the device is activated, for
+example, after every reboot.
+
+The optional argument --replicatorlogtype specifies type of the backing store
+log. The default and currently the only valid and supported type is
+\fBringbuffer\fP.
+
+The optional argument --site creates \fIsite\fP in replicator. Site could have
+operation mode {sync|warn|stall|drop|fail}. For asynchronous modes one
+of the following fall behind parameters must be specified: --fallbehinddata,
+--fallbehindios, --fallbehindtimeout (see \fBlvchange\fP(8)).
+For remote sites --remotevg specifies the name of
+the remote volume group. Note: current implementation expects
+that any remote volume group contains prepared logical volumes
+with the same size and name as the local replicated logical volumes.
+
+.TP
+.I \-\-replicatordev
+Creates empty replicated logical volume in the local site
+of given Replicator.
 
 .TP
 .I \-n, \-\-name LogicalVolumeName
@@ -246,10 +303,29 @@ under 100MB of actual data on it.
 creates a linear logical volume "vg00/lvol1" using physical extents
 /dev/sda:0-7 and /dev/sdb:0-7 for allocation of extents.
 
+"lvcreate --replicator -L 1G -n rep0 vg00"
+.br
+creates a replicator "vg00/rep0" and hidden replicator backing store device
+"vg00/rep0_rlog" of size 1G.
+
+"lvcreate --site Remote --remotevg remotevg00 --fallbehinddata 100M
+--replicator vg00/rep0"
+.br
+creates the remote site named Remote in replicator "vg00/rep0"
+that uses remote volume group "remotevg00" and could get upto 100MiB
+asynchronous behind replicated volume.
+Current implementation needs remote LVs created by hand
+in the remote volume group "remotevg00".
+
+"lvcreate --replicatordev -n lvol1 -L 64M --replicator vg00/rep0"
+.br
+creates a replicated device named "vg00/lvol1" of size 64M attached to
+the local site in the replicator "vg00/rep0".
 
 .SH SEE ALSO
 .BR lvm (8), 
 .BR vgcreate (8), 
+.BR lvchange (8),
 .BR lvremove (8), 
 .BR lvrename (8)
 .BR lvextend (8), 
Signature · 1 line
1.7.1.1
#20 lore raw

PATCH 20/22 Replicator: lvchange implementation

In reply to Zdenek Kabelac
---
 tools/commands.h |    6 ++
 tools/lvchange.c |  195 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 196 insertions(+), 5 deletions(-)
tools/commands.h +6 -0
index 7966cff..9e27ad9 100644
@@ -80,6 +80,10 @@ xx(lvchange,
    "\t[-r|--readahead ReadAheadSectors|auto|none]\n"
    "\t[--refresh]\n"
    "\t[--resync]\n"
+   "\t[--replicator ReplicatorName]\n"
+   "\t[--site SiteName [--sitemode {sync|warn|stall|drop|fail}]\n"
+   "\t  [{--fallbehinddata Size[bBsSkKmMgG]|\n"
+   "\t    --fallbehindios IOCount|--fallbehindtimeout Secs}]]]\n"
    "\t[--sysinit]\n"
    "\t[-t|--test]\n"
    "\t[-v|--verbose]\n"
@@ -91,6 +95,8 @@ xx(lvchange,
    ignorelockingfailure_ARG, ignoremonitoring_ARG, major_ARG, minor_ARG,
    monitor_ARG, noudevsync_ARG, partial_ARG, permission_ARG, persistent_ARG,
    poll_ARG, readahead_ARG, resync_ARG, refresh_ARG, addtag_ARG, deltag_ARG,
+   fallbehinddata_ARG, fallbehindios_ARG, fallbehindtimeout_ARG,
+   replicator_ARG, replicatorlogtype_ARG, remotevg_ARG, site_ARG, sitemode_ARG,
    sysinit_ARG, test_ARG, yes_ARG)
 
 xx(lvconvert,
tools/lvchange.c +190 -5

250 lines not on this page · raw message

Signature · 1 line
1.7.1.1
#21 lore raw

PATCH 21/22 Replicator: man page update for lvchange

In reply to Zdenek Kabelac

Update lvchange man page to cover basic usability commands.

---
 man/lvchange.8.in |   31 +++++++++++++++++++++++++++++++
 1 files changed, 31 insertions(+), 0 deletions(-)
man/lvchange.8.in +31 -0
index e269802..6899613 100644
@@ -7,6 +7,11 @@ lvchange \- change attributes of a logical volume
 [\-A|\-\-autobackup y|n] [\-a|\-\-available y|n|ey|en|ly|ln]
 [\-\-alloc AllocationPolicy]
 [\-C|\-\-contiguous y|n] [\-d|\-\-debug] [\-\-deltag Tag]
+[[\-\-site Site]
+[\-\-sitemode [sync|warn|stall|drop|fail]
+{[\-\-fallbehinddata Size[bBsSkKmMgGtTpPeE]] |
+[\-\-fallbehindios  IOS] |
+[\-\-fallbehindtimeout sec]}]
 [\-\-resync]
 [\-h|\-?|\-\-help]
 [\-\-ignorelockingfailure]
@@ -112,10 +117,36 @@ If the logical volume is active, reload its metadata.
 This is not necessary in normal operation, but may be useful
 if something has gone wrong or if you're doing clustering 
 manually without a clustered lock manager.
+.TP
+.I \-\-fallbehinddata
+How many data could get replicator behind. Cannot be mixed
+with --fallbehindios or --fallbehindtimeout.
+.TP
+.I \-\-fallbehindios
+How many io operation could be queued in replicator backing store device.
+Cannot be mixed with --fallbehinddata or --fallbehindtimeout.
+.TP
+.I \-\-fallbehindtimeout
+How many seconds could be replicator behind actual data. Cannot be mixed
+with --fallbehinddata or --fallbehindios.
+.TP
+.I \-\-sitemode
+Select replication mode. Default is Warn.
+Sync is synchronous mode. Warn,Stall,Drop,Fail are asynchronous modes.
+Warn issues warning when remote site is switched to sync log.
+Stall stalls replicator until remote site is back in range.
+Drop drops whole remote site, if it get too behind.
+Fail whole replicator fails is remote sites gets too behind.
+Local site works usually in stall mode. There is no synclog for local
+replicated volumes.
+.TP
 .SH Examples
 "lvchange -pr vg00/lvol1" changes the permission on 
 volume lvol1 in volume group vg00 to be read-only.
 
+"lvchange --site Berlin -ay vg00/L1"
+marks the local site Berlin for LV "vg00/L1" as active.
+
 .SH SEE ALSO
 .BR lvm (8), 
 .BR lvcreate (8),
Signature · 1 line
1.7.1.1
#22 lore raw

PATCH 22/22 Replicator: lvremove implementation

In reply to Zdenek Kabelac
---
 tools/commands.h |    3 ++-
 tools/lvremove.c |   19 ++++++++++++++++++-
 2 files changed, 20 insertions(+), 2 deletions(-)
tools/commands.h +2 -1
index 9e27ad9..73bede8 100644
@@ -365,12 +365,13 @@ xx(lvremove,
    "\t[-f|--force]\n"
    "\t[-h|--help]\n"
    "\t[--noudevsync]\n"
+   "\t[--site SiteName]\n"
    "\t[-t|--test]\n"
    "\t[-v|--verbose]\n"
    "\t[--version]" "\n"
    "\tLogicalVolume[Path] [LogicalVolume[Path]...]\n",
 
-   autobackup_ARG, force_ARG, noudevsync_ARG, test_ARG)
+   autobackup_ARG, force_ARG, noudevsync_ARG, site_ARG, test_ARG)
 
 xx(lvrename,
    "Rename a logical volume",
tools/lvremove.c +18 -1
index dbf2f1d..15005c3 100644
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2010 Red Hat, Inc. All rights reserved.
  *
  * This file is part of LVM2.
  *
@@ -19,6 +19,8 @@ static int lvremove_single(struct cmd_context *cmd, struct logical_volume *lv,
 			   void *handle __attribute((unused)))
 {
 	struct logical_volume *origin;
+	struct logical_volume *replicator;
+	const char *site_name;
 
 	/*
 	 * If this is a sparse device, remove its origin too.
@@ -26,6 +28,21 @@ static int lvremove_single(struct cmd_context *cmd, struct logical_volume *lv,
         if (lv_is_cow(lv) && lv_is_virtual_origin(origin = origin_from_cow(lv)))
                 lv = origin;
 
+	if ((lv_is_replicator_dev(lv) || lv_is_replicator(lv)) &&
+	    arg_count(cmd, site_ARG)) {
+		replicator = lv_is_replicator(lv) ? lv : first_seg(lv)->replicator;
+		site_name = arg_str_value(cmd, site_ARG,
+					  DEFAULT_REPLICATOR_LOCAL_SITE_NAME);
+
+		log_error("REMOVE SITE  %s   of %s", site_name, replicator->name);
+		if (!lv_remove_replicator_site(replicator, site_name)) {
+			stack;
+			return ECMD_FAILED;
+		}
+
+		return ECMD_PROCESSED;
+	}
+
 	if (!lv_remove_with_dependencies(cmd, lv, arg_count(cmd, force_ARG), 0)) {
 		stack;
 		return ECMD_FAILED;
Signature · 1 line
1.7.1.1