* [PATCH 01/12] Allow the user to not specify a size when creating snapshot.
2010-06-29 16:26 [PATCH 00/12] Replicator 100629 Zdenek Kabelac
@ 2010-06-29 16:26 ` Zdenek Kabelac
2010-06-29 16:26 ` [PATCH 02/12] Replicator: check for active replicator Zdenek Kabelac
` (10 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Zdenek Kabelac @ 2010-06-29 16:26 UTC (permalink / raw)
To: lvm-devel
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.
Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
Reviewed-by: Zdenek Kabelac <zkabelac@redhat.com>
---
tools/lvcreate.c | 4 ++++
1 files changed, 4 insertions(+), 0 deletions(-)
diff --git a/tools/lvcreate.c b/tools/lvcreate.c
index d0e962f..9e167aa 100644
--- a/tools/lvcreate.c
+++ b/tools/lvcreate.c
@@ -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) {
--
1.7.1
^ permalink raw reply related [flat|nested] 13+ messages in thread* [PATCH 02/12] Replicator: check for active replicator
2010-06-29 16:26 [PATCH 00/12] Replicator 100629 Zdenek Kabelac
2010-06-29 16:26 ` [PATCH 01/12] Allow the user to not specify a size when creating snapshot Zdenek Kabelac
@ 2010-06-29 16:26 ` Zdenek Kabelac
2010-06-29 16:26 ` [PATCH 03/12] Replicator: reserved names Zdenek Kabelac
` (9 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Zdenek Kabelac @ 2010-06-29 16:26 UTC (permalink / raw)
To: lvm-devel
Skip activation of other heads only for a active replicator.
For inactive active all heads with linear overlay mapping
Signed-off-by: Zdenek Kabelac <zkabelac@redhat.com>
---
tools/vgchange.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/tools/vgchange.c b/tools/vgchange.c
index 1d3e321..5a9edd8 100644
--- a/tools/vgchange.c
+++ b/tools/vgchange.c
@@ -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 */
--
1.7.1
^ permalink raw reply related [flat|nested] 13+ messages in thread* [PATCH 03/12] Replicator: reserved names
2010-06-29 16:26 [PATCH 00/12] Replicator 100629 Zdenek Kabelac
2010-06-29 16:26 ` [PATCH 01/12] Allow the user to not specify a size when creating snapshot Zdenek Kabelac
2010-06-29 16:26 ` [PATCH 02/12] Replicator: check for active replicator Zdenek Kabelac
@ 2010-06-29 16:26 ` Zdenek Kabelac
2010-06-29 16:26 ` [PATCH 04/12] Replicator: add _replicator_in_sync Zdenek Kabelac
` (8 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Zdenek Kabelac @ 2010-06-29 16:26 UTC (permalink / raw)
To: lvm-devel
Signed-off-by: Zdenek Kabelac <zkabelac@redhat.com>
---
lib/misc/lvm-string.c | 18 ++++++++++++++++++
1 files changed, 18 insertions(+), 0 deletions(-)
diff --git a/lib/misc/lvm-string.c b/lib/misc/lvm-string.c
index 7eed799..fb73674 100644
--- a/lib/misc/lvm-string.c
+++ b/lib/misc/lvm-string.c
@@ -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;
}
--
1.7.1
^ permalink raw reply related [flat|nested] 13+ messages in thread* [PATCH 04/12] Replicator: add _replicator_in_sync
2010-06-29 16:26 [PATCH 00/12] Replicator 100629 Zdenek Kabelac
` (2 preceding siblings ...)
2010-06-29 16:26 ` [PATCH 03/12] Replicator: reserved names Zdenek Kabelac
@ 2010-06-29 16:26 ` Zdenek Kabelac
2010-06-29 16:26 ` [PATCH 05/12] Replicator: improve detection of replicator-dev Zdenek Kabelac
` (7 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Zdenek Kabelac @ 2010-06-29 16:26 UTC (permalink / raw)
To: lvm-devel
Add function init_replicator_in_sync() to be similar as mirror.
For now this function is not functional.
Signed-off-by: Zdenek Kabelac <zkabelac@redhat.com>
---
lib/misc/lvm-globals.c | 11 +++++++++++
lib/misc/lvm-globals.h | 2 ++
2 files changed, 13 insertions(+), 0 deletions(-)
diff --git a/lib/misc/lvm-globals.c b/lib/misc/lvm-globals.c
index 8dc2b02..5334691 100644
--- a/lib/misc/lvm-globals.c
+++ b/lib/misc/lvm-globals.c
@@ -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;
diff --git a/lib/misc/lvm-globals.h b/lib/misc/lvm-globals.h
index 0134c32..c08aa2e 100644
--- a/lib/misc/lvm-globals.h
+++ b/lib/misc/lvm-globals.h
@@ -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);
--
1.7.1
^ permalink raw reply related [flat|nested] 13+ messages in thread* [PATCH 05/12] Replicator: improve detection of replicator-dev
2010-06-29 16:26 [PATCH 00/12] Replicator 100629 Zdenek Kabelac
` (3 preceding siblings ...)
2010-06-29 16:26 ` [PATCH 04/12] Replicator: add _replicator_in_sync Zdenek Kabelac
@ 2010-06-29 16:26 ` Zdenek Kabelac
2010-06-29 16:26 ` [PATCH 06/12] Replicator: lvcreate, lvm man pages Zdenek Kabelac
` (6 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Zdenek Kabelac @ 2010-06-29 16:26 UTC (permalink / raw)
To: lvm-devel
Check for NULL replicator pointer in replicator-dev segment.
Signed-off-by: Zdenek Kabelac <zkabelac@redhat.com>
---
lib/metadata/merge.c | 18 ++++++++++++------
1 files changed, 12 insertions(+), 6 deletions(-)
diff --git a/lib/metadata/merge.c b/lib/metadata/merge.c
index 3b8895c..11c58f9 100644
--- a/lib/metadata/merge.c
+++ b/lib/metadata/merge.c
@@ -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++;
--
1.7.1
^ permalink raw reply related [flat|nested] 13+ messages in thread* [PATCH 06/12] Replicator: lvcreate, lvm man pages
2010-06-29 16:26 [PATCH 00/12] Replicator 100629 Zdenek Kabelac
` (4 preceding siblings ...)
2010-06-29 16:26 ` [PATCH 05/12] Replicator: improve detection of replicator-dev Zdenek Kabelac
@ 2010-06-29 16:26 ` Zdenek Kabelac
2010-06-29 16:26 ` [PATCH 07/12] Replicator: add new options for replicator Zdenek Kabelac
` (5 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Zdenek Kabelac @ 2010-06-29 16:26 UTC (permalink / raw)
To: lvm-devel
Update man pages to cover basic usage of lvcreate
Current descriptions shows how to create replicator,
add site, add replicated device.
Signed-off-by: Zdenek Kabelac <zkabelac@redhat.com>
---
man/lvcreate.8.in | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++++
man/lvm.8.in | 3 +-
2 files changed, 68 insertions(+), 1 deletions(-)
diff --git a/man/lvcreate.8.in b/man/lvcreate.8.in
index 0d0976f..ce9c078 100644
--- a/man/lvcreate.8.in
+++ b/man/lvcreate.8.in
@@ -36,6 +36,26 @@ VolumeGroupName [PhysicalVolumePath[:PE[-PE]]...]
OriginalLogicalVolumePath |
[\-s|\-\-snapshot]
VolumeGroupName \-\-virtualsize VirtualSize}
+.br
+
+.br
+.B lvcreate
+{\-l|\-\-extents LogicalExtentsNumber[%{VG|FREE|ORIGIN}] |
+ \-L|\-\-size LogicalVolumeSize[bBsSkKmMgGtTpPeE]}
+[\-\-replicatorlogtype ReplicatorLogType]
+{[\-\-replicatorsynclog {disk|core}] | [\-\-corelog]}
+[\-R|\-\-regionsize ReplicatorSyncLogRegionSize]]
+{[\-\-fallbehinddata Size[bBsSkKmMgGtTpPeE]] |
+[\-\-fallbehindios IOS] |
+[\-\-fallbehindtimeout sec]}
+[\-\-sitemode [sync|warn|stall|drop|fail]
+[\-\-remotevg RemoteVolumeGroupName]
+[\-\-nosync]
+\-n|\-\-name ReplicatorName
+\-\-replicator [ReplicatorName[Path]]
+VolumeGroupName
+.br
+
.SH DESCRIPTION
lvcreate creates a new logical volume in a volume group ( see
.B vgcreate(8), vgchange(8)
@@ -52,6 +72,9 @@ 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 replicator logical volumes which
+keep the contents of the replicators.
.SH OPTIONS
See \fBlvm\fP for common options.
.TP
@@ -120,6 +143,33 @@ 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
+.B lvchange(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.
+
+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.
+
+
+.TP
+.I \-\-replicatordev
+Creates empty replicated logical volume in given ReplicatorName.
+(Future: If the --site is not specified, local site is found inside replicator LV.)
.TP
.I \-n, \-\-name LogicalVolumeName
@@ -246,10 +296,26 @@ 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 --replicator vg00/rep0 --site Remote --remotevg remotevg00 --fallbehinddata 100M"
+.br
+creates a remote site Remote in replicator vg00/rep0 which uses remote volume group
+remotevg00 and could get upto 100MiB asynchronous behind replicated volume.
+For this version remote LVs must be created by hand in remote volume group.
+
+"lvcreate --replicatordev -n lvol1 -L 64M --replicator vg00/rep0"
+.br
+creates a replicated device named /dev/vg00/lvol1 of size 64M attached to replicator
+vg00/rep0.
.SH SEE ALSO
.BR lvm (8),
.BR vgcreate (8),
+.BR lvchange (8),
.BR lvremove (8),
.BR lvrename (8)
.BR lvextend (8),
diff --git a/man/lvm.8.in b/man/lvm.8.in
index e38ce4f..7d070f7 100644
--- a/man/lvm.8.in
+++ b/man/lvm.8.in
@@ -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
--
1.7.1
^ permalink raw reply related [flat|nested] 13+ messages in thread* [PATCH 07/12] Replicator: add new options for replicator
2010-06-29 16:26 [PATCH 00/12] Replicator 100629 Zdenek Kabelac
` (5 preceding siblings ...)
2010-06-29 16:26 ` [PATCH 06/12] Replicator: lvcreate, lvm man pages Zdenek Kabelac
@ 2010-06-29 16:26 ` Zdenek Kabelac
2010-06-29 16:26 ` [PATCH 08/12] Replicator: lv_manip - create replicator Zdenek Kabelac
` (4 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Zdenek Kabelac @ 2010-06-29 16:26 UTC (permalink / raw)
To: lvm-devel
New options for lvcreate:
replicator, replicatordev, replicatorlogtype, replicatorsynclog,
remotevg, site, sitemode
Signed-off-by: Zdenek Kabelac <zkabelac@redhat.com>
---
lib/config/defaults.h | 8 ++
lib/metadata/metadata-exported.h | 46 +++++++++++--
tools/args.h | 10 +++
tools/commands.h | 15 ++++
tools/lvcreate.c | 134 +++++++++++++++++++++++++++++++++++++-
tools/lvmcmdline.c | 10 +++
tools/tools.h | 1 +
7 files changed, 213 insertions(+), 11 deletions(-)
diff --git a/lib/config/defaults.h b/lib/config/defaults.h
index 0d8cb9c..644809d 100644
--- a/lib/config/defaults.h
+++ b/lib/config/defaults.h
@@ -48,6 +48,13 @@
#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_UMASK 0077
#ifdef LVM1_FALLBACK
@@ -104,6 +111,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
diff --git a/lib/metadata/metadata-exported.h b/lib/metadata/metadata-exported.h
index 26ba545..8b2dd66 100644
--- a/lib/metadata/metadata-exported.h
+++ b/lib/metadata/metadata-exported.h
@@ -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 */
@@ -349,7 +350,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 */
@@ -617,6 +618,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 */
@@ -635,6 +638,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 */
@@ -798,17 +804,22 @@ 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,
+int replicator_site_add_device(struct replicator_site *rsite,
+ struct lv_segment *replicator_dev_seg,
+ const char *name,
+ struct logical_volume *rimage_lv,
+ uint32_t slog_core,
+ struct logical_volume *slog_lv,
+ uint64_t device_index);
+int replicator_site_remove_device(struct replicator_device *rdev);
+int replicator_add_replicator_dev(struct logical_volume *replicator,
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);
-
+struct replicator_site *replicator_add_site(struct logical_volume *replicator,
+ const char *site_name);
+int replicator_remove_site(struct replicator_site *rsite);
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);
@@ -816,6 +827,25 @@ int lv_is_rimage(const struct logical_volume *lv);
int lv_is_rlog(const struct logical_volume *lv);
int lv_is_slog(const struct logical_volume *lv);
struct logical_volume *first_replicator_dev(const struct logical_volume *lv);
+int vg_prepare_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);
+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 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);
+struct replicator_site *find_site_in_replicator(struct logical_volume *replicator,
+ const char *site_name);
/* -- 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,
diff --git a/tools/args.h b/tools/args.h
index ebce252..eab9b51 100644
--- a/tools/args.h
+++ b/tools/args.h
@@ -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", string_arg, 0)
+arg(remotevg_ARG, '\0', "remotevg", string_arg, 0)
/* Allow some variations */
arg(resizable_ARG, '\0', "resizable", yes_no_arg, 0)
diff --git a/tools/commands.h b/tools/commands.h
index aa012a7..a300774 100644
--- a/tools/commands.h
+++ b/tools/commands.h
@@ -118,6 +118,12 @@ xx(lvconvert,
"\tLogicalVolume[Path] [SplittablePhysicalVolume[Path]...]\n\n"
"lvconvert "
+ "--replicator\n"
+ "\t[-d|--debug]\n"
+ "\t[-h|-?|--help]\n"
+ "\t[-v|--verbose]\n"
+
+ "lvconvert "
"[-s|--snapshot]\n"
"\t[-c|--chunksize]\n"
"\t[-d|--debug]\n"
@@ -165,6 +171,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 +215,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,
diff --git a/tools/lvcreate.c b/tools/lvcreate.c
index 9e167aa..8cb1e24 100644
--- a/tools/lvcreate.c
+++ b/tools/lvcreate.c
@@ -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.
*
@@ -60,7 +60,10 @@ static int _lvcreate_name_params(struct lvcreate_params *lp,
* environment.
*/
if (!argc) {
- if (!(lp->vg_name = extract_vgname(cmd, lp->lv_name))) {
+ if (!(lp->vg_name = extract_vgname(cmd, lp->lv_name)) &&
+ /* try to detect vg name from --replicator arg */
+ (lp->replicator &&
+ !(lp->vg_name = extract_vgname(cmd, lp->replicator)))) {
log_error("Please provide a volume group name");
return 0;
}
@@ -73,6 +76,11 @@ static int _lvcreate_name_params(struct lvcreate_params *lp,
return 0;
}
+ if (!lp->lv_name &&
+ !lp->replicator_dev &&
+ lp->replicator &&
+ strlen(lp->replicator))
+ lp->lv_name = lp->replicator;
/*
* Ensure lv_name doesn't contain a
* different VG.
@@ -116,6 +124,20 @@ static int _lvcreate_name_params(struct lvcreate_params *lp,
}
}
+ if (lp->replicator) {
+ if ((ptr = strrchr(lp->replicator, '/')))
+ lp->replicator = ptr + 1;
+
+ if (!apply_lvname_restrictions(lp->replicator))
+ return_0;
+
+ if (!validate_name(lp->replicator)) {
+ log_error("Logical volume name \"%s\" is invalid",
+ lp->replicator);
+ return 0;
+ }
+ }
+
return 1;
}
@@ -315,7 +337,82 @@ static int _read_mirror_params(struct lvcreate_params *lp,
}
if (!_validate_mirror_params(cmd, lp))
+ return_0;
+
+ return 1;
+}
+
+static int _read_replicator_params(struct lvcreate_params *lp,
+ struct cmd_context *cmd)
+{
+ int region_size;
+ const char *replicatorsynclog;
+ int corelog = arg_count(cmd, corelog_ARG);
+
+ if (arg_count(cmd, sitemode_ARG)) {
+ log_error("FIXME: Sorry, sitemode parameter is not yet supported.");
+ return 0;
+ }
+
+ replicatorsynclog = arg_str_value(cmd, replicatorsynclog_ARG,
+ corelog ? "core" : DEFAULT_REPLICATOR_SYNCLOG);
+
+ if (strcmp("core", replicatorsynclog) && corelog) {
+ log_error("Please use only one of --replicatorlog or --corelog");
return 0;
+ }
+
+ if (!strcmp("disk", replicatorsynclog))
+ lp->log_count = 1;
+ else if (!strcmp("core", replicatorsynclog))
+ lp->log_count = 0;
+ else {
+ log_error("Unknown replicatorsynclog type: %s", replicatorsynclog);
+ return 0;
+ }
+
+ log_verbose("Setting sync logging type to %s", replicatorsynclog);
+ if (arg_count(cmd, regionsize_ARG)) {
+ if (arg_sign_value(cmd, regionsize_ARG, 0) == SIGN_MINUS) {
+ log_error("Negative regionsize is invalid.");
+ return 0;
+ }
+ lp->region_size = arg_uint_value(cmd, regionsize_ARG, 0);
+ } else {
+ region_size = 2 * find_config_tree_int(cmd,
+ "activation/replicator_region_size",
+ DEFAULT_REPLICATOR_REGION_SIZE);
+ if (region_size < 0) {
+ log_error("Negative replicator_region_size in configuration "
+ "file is invalid.");
+ return 0;
+ }
+ lp->region_size = region_size;
+ }
+
+ if (!_validate_mirror_params(cmd, lp)) /* reuse for mirror's region_size */
+ return 0;
+
+ lp->rlog_type = arg_str_value(cmd, replicatorlogtype_ARG,
+ DEFAULT_REPLICATOR_LOG_TYPE);
+
+ if (strcmp(lp->rlog_type, DEFAULT_REPLICATOR_LOG_TYPE)) {
+ log_error("Unsupported replicator log type %s", lp->rlog_type);
+ return 0;
+ }
+
+ lp->rsite.fall_behind_data = arg_uint64_value(cmd, fallbehinddata_ARG,
+ DEFAULT_REPLICATOR_FALL_BEHIND_DATA);
+ lp->rsite.fall_behind_ios = arg_uint_value(cmd, fallbehindios_ARG,
+ DEFAULT_REPLICATOR_FALL_BEHIND_IOS);
+ lp->rsite.fall_behind_timeout = arg_uint_value(cmd, fallbehindtimeout_ARG,
+ DEFAULT_REPLICATOR_FALL_BEHIND_TIMEOUT);
+
+ if (arg_count(cmd, site_ARG))
+ lp->rsite.name = arg_str_value(cmd, site_ARG,
+ DEFAULT_REPLICATOR_LOCAL_SITE_NAME);
+ if (arg_count(cmd, remotevg_ARG))
+ lp->rsite.vg_name = arg_str_value(cmd, remotevg_ARG, NULL);
return 1;
}
@@ -327,6 +424,7 @@ static int _lvcreate_params(struct lvcreate_params *lp,
{
int contiguous;
unsigned pagesize;
+ int i;
memset(lp, 0, sizeof(*lp));
memset(lcp, 0, sizeof(*lcp));
@@ -346,6 +444,12 @@ static int _lvcreate_params(struct lvcreate_params *lp,
if (seg_is_mirrored(lp))
lp->mirrors = 2;
+ if (seg_is_replicator(lp) || arg_count(cmd, replicator_ARG))
+ lp->replicator = arg_str_value(cmd, replicator_ARG, "");
+
+ if (seg_is_replicator_dev(lp) || arg_count(cmd, replicatordev_ARG))
+ lp->replicator_dev = 1;
+
if (arg_count(cmd, mirrors_ARG)) {
lp->mirrors = arg_uint_value(cmd, mirrors_ARG, 0) + 1;
if (lp->mirrors == 1)
@@ -383,7 +487,7 @@ static int _lvcreate_params(struct lvcreate_params *lp,
}
}
- if (lp->mirrors > 1) {
+ if (lp->mirrors > 1 || lp->replicator) {
if (lp->snapshot) {
log_error("mirrors and snapshots are currently "
"incompatible");
@@ -409,6 +513,29 @@ static int _lvcreate_params(struct lvcreate_params *lp,
}
}
+ if (!lp->replicator) {
+ static const struct {
+ const char *str;
+ int argname;
+ } repargs[] = {
+ { "fallbehinddata", fallbehinddata_ARG },
+ { "fallbehindios", fallbehindios_ARG },
+ { "fallbehindtimeout", fallbehindtimeout_ARG },
+ { "remotevg", remotevg_ARG },
+ { "replicatorlogtype", replicatorlogtype_ARG },
+ { "replicatorsynclog", replicatorsynclog_ARG },
+ { "site", site_ARG },
+ { "sitemode", sitemode_ARG }
+ };
+
+ for (i = 0; i < sizeof(repargs)/sizeof(repargs[0]); ++i)
+ if (arg_count(cmd, repargs[i].argname)) {
+ log_error("--%s is only available "
+ "with replicators.", repargs[i].str);
+ return 0;
+ }
+ }
+
if (activation() && lp->segtype->ops->target_present &&
!lp->segtype->ops->target_present(cmd, NULL, NULL)) {
log_error("%s: Required device-mapper target(s) not "
@@ -423,6 +550,7 @@ static int _lvcreate_params(struct lvcreate_params *lp,
if (!_lvcreate_name_params(lp, cmd, &argc, &argv) ||
!_read_size_params(lp, lcp, cmd) ||
!get_stripe_params(cmd, &lp->stripes, &lp->stripe_size) ||
+ !_read_replicator_params(lp, cmd) ||
!_read_mirror_params(lp, cmd))
return_0;
diff --git a/tools/lvmcmdline.c b/tools/lvmcmdline.c
index 4652888..f4f9d86 100644
--- a/tools/lvmcmdline.c
+++ b/tools/lvmcmdline.c
@@ -473,6 +473,16 @@ 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;
+}
+
/*
* Non-zero, positive integer, "all", or "unmanaged"
*/
diff --git a/tools/tools.h b/tools/tools.h
index a09fa8e..c615b09 100644
--- a/tools/tools.h
+++ b/tools/tools.h
@@ -152,6 +152,7 @@ int units_arg(struct cmd_context *cmd, struct arg *a);
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 site_arg(struct cmd_context *cmd, struct arg *a);
int vgmetadatacopies_arg(struct cmd_context *cmd __attribute((unused)),
struct arg *a);
--
1.7.1
^ permalink raw reply related [flat|nested] 13+ messages in thread* [PATCH 08/12] Replicator: lv_manip - create replicator
2010-06-29 16:26 [PATCH 00/12] Replicator 100629 Zdenek Kabelac
` (6 preceding siblings ...)
2010-06-29 16:26 ` [PATCH 07/12] Replicator: add new options for replicator Zdenek Kabelac
@ 2010-06-29 16:26 ` Zdenek Kabelac
2010-06-29 16:26 ` [PATCH 09/12] Replicator: add report for replicator targets Zdenek Kabelac
` (3 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Zdenek Kabelac @ 2010-06-29 16:26 UTC (permalink / raw)
To: lvm-devel
Signed-off-by: Zdenek Kabelac <zkabelac@redhat.com>
---
lib/metadata/lv_manip.c | 126 ++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 125 insertions(+), 1 deletions(-)
diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c
index 5e4a674..b817eb5 100644
--- a/lib/metadata/lv_manip.c
+++ b/lib/metadata/lv_manip.c
@@ -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_prepare_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))
--
1.7.1
^ permalink raw reply related [flat|nested] 13+ messages in thread* [PATCH 09/12] Replicator: add report for replicator targets
2010-06-29 16:26 [PATCH 00/12] Replicator 100629 Zdenek Kabelac
` (7 preceding siblings ...)
2010-06-29 16:26 ` [PATCH 08/12] Replicator: lv_manip - create replicator Zdenek Kabelac
@ 2010-06-29 16:26 ` Zdenek Kabelac
2010-06-29 16:26 ` [PATCH 10/12] Replicator: replicator_manip changes Zdenek Kabelac
` (2 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Zdenek Kabelac @ 2010-06-29 16:26 UTC (permalink / raw)
To: lvm-devel
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.
Signed-off-by: Zdenek Kabelac <zkabelac@redhat.com>
---
lib/report/columns.h | 2 ++
lib/report/report.c | 32 ++++++++++++++++++++++++++++++++
2 files changed, 34 insertions(+), 0 deletions(-)
diff --git a/lib/report/columns.h b/lib/report/columns.h
index 823ce2c..b6e00ef 100644
--- a/lib/report/columns.h
+++ b/lib/report/columns.h
@@ -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.")
diff --git a/lib/report/report.c b/lib/report/report.c
index 9a76334..b7fb15b 100644
--- a/lib/report/report.c
+++ b/lib/report/report.c
@@ -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)
--
1.7.1
^ permalink raw reply related [flat|nested] 13+ messages in thread* [PATCH 10/12] Replicator: replicator_manip changes
2010-06-29 16:26 [PATCH 00/12] Replicator 100629 Zdenek Kabelac
` (8 preceding siblings ...)
2010-06-29 16:26 ` [PATCH 09/12] Replicator: add report for replicator targets Zdenek Kabelac
@ 2010-06-29 16:26 ` Zdenek Kabelac
2010-06-29 16:26 ` [PATCH 11/12] Replicator: replicator.c changes Zdenek Kabelac
2010-06-29 16:26 ` [PATCH 12/12] Replicator: man pages for lvchange.8 Zdenek Kabelac
11 siblings, 0 replies; 13+ messages in thread
From: Zdenek Kabelac @ 2010-06-29 16:26 UTC (permalink / raw)
To: lvm-devel
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.
Signed-off-by: Zdenek Kabelac <zkabelac@redhat.com>
---
lib/metadata/replicator_manip.c | 806 +++++++++++++++++++++++++++++++++++----
1 files changed, 741 insertions(+), 65 deletions(-)
diff --git a/lib/metadata/replicator_manip.c b/lib/metadata/replicator_manip.c
index b3a2fff..c6000aa 100644
--- a/lib/metadata/replicator_manip.c
+++ b/lib/metadata/replicator_manip.c
@@ -15,19 +15,25 @@
#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"
/* Add lv as replicator_dev device */
-int replicator_dev_add_rimage(struct replicator_device *rdev,
- struct logical_volume *lv)
+static int _replicator_device_add_rimage(struct replicator_device *rdev,
+ struct logical_volume *lv)
{
if (!lv || !rdev)
return_0;
if (lv_is_rimage(lv)) {
+
log_error("Logical volume %s is already part of other "
- "replicator.", lv->name);
+ "replicator. %p %p", lv->name, lv->rdevice, rdev);
return 0;
}
@@ -39,13 +45,14 @@ int replicator_dev_add_rimage(struct replicator_device *rdev,
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;
@@ -64,8 +71,8 @@ struct logical_volume *replicator_dev_remove_rimage(struct replicator_device *rd
return lv;
}
-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;
@@ -89,15 +96,14 @@ int replicator_dev_add_slog(struct replicator_device *rdev,
return add_seg_to_segs_using_this_lv(slog, rdev->replicator_dev);
}
-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;
if (!rdev)
return_NULL;
- lv = rdev->slog;
- if (!lv) {
+ if (!(lv = rdev->slog)) {
log_error("Replicator device in site %s does not have sync log.",
rdev->rsite->name);
return NULL;
@@ -113,16 +119,40 @@ struct logical_volume *replicator_dev_remove_slog(struct replicator_device *rdev
return lv;
}
-int replicator_add_replicator_dev(struct logical_volume *replicator_lv,
+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;
+}
+
+/*
+ * Connection of NULL lv_segment will turn LV into replicator LV
+ */
+int replicator_add_replicator_dev(struct logical_volume *replicator,
struct lv_segment *replicator_dev_seg)
{
- if (!replicator_lv)
+ if (!replicator)
return_0;
- if (!(replicator_lv->status & REPLICATOR)) {
- dm_list_init(&replicator_lv->rsites);
- lv_set_hidden(replicator_lv);
- replicator_lv->status |= REPLICATOR;
+ if (!(replicator->status & REPLICATOR)) {
+ dm_list_init(&replicator->rsites);
+ lv_set_hidden(replicator);
+ replicator->status |= REPLICATOR;
}
if (!replicator_dev_seg)
@@ -134,9 +164,11 @@ int replicator_add_replicator_dev(struct logical_volume *replicator_lv,
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;
- return add_seg_to_segs_using_this_lv(replicator_lv, replicator_dev_seg);
+ return add_seg_to_segs_using_this_lv(replicator, replicator_dev_seg);
}
/**
@@ -145,25 +177,25 @@ int replicator_add_replicator_dev(struct logical_volume *replicator_lv,
*/
struct logical_volume *replicator_remove_replicator_dev(struct lv_segment *replicator_dev_seg)
{
- struct logical_volume *lv = NULL;
-
- log_error("FIXME: not implemented.");
-#if 0
- /* FIXME: - this is going to be complex.... */
if (!replicator_dev_seg)
return_NULL;
- /* if slog or rimage - exit */
+ if (!_replicator_device_remove_rimage(replicator_dev_seg->lv->rdevice)) {
+ log_error("Can not release rimage device");
+ return NULL;
+ }
- if (!remove_seg_from_segs_using_this_lv(lv, replicator_seg))
+ if (!remove_seg_from_segs_using_this_lv(replicator_dev_seg->replicator, replicator_dev_seg))
return_NULL;
- replicator_seg->rlog_lv = NULL;
- lv->status &= ~REPLICATOR_LOG;
- lv_set_visible(lv);
-#endif
+ dm_list_del(&replicator_dev_seg->lv->rdevice->list);
- return lv;
+ replicator_dev_seg->lv->status &= ~REPLICATOR;
+ replicator_dev_seg->rlog_lv = NULL;
+ replicator_dev_seg->replicator = NULL;
+ lv_set_visible(replicator_dev_seg->lv);
+
+ return replicator_dev_seg->lv;
}
int replicator_add_rlog(struct lv_segment *replicator_seg,
@@ -207,52 +239,232 @@ struct logical_volume *replicator_remove_rlog(struct lv_segment *replicator_seg)
return lv;
}
+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 (!(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;
+}
+
+int replicator_remove_site(struct replicator_site *rsite)
+{
+ log_error("FIXME: replicator_remove_site implementation is missing.");
+ dm_list_del(&rsite->list);
+
+ return 1;
+}
+
+int replicator_site_add_device(struct replicator_site *rsite,
+ struct lv_segment *replicator_dev_seg,
+ const char *name,
+ struct logical_volume *rimage_lv,
+ 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, 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_lv && !_replicator_device_add_rimage(rdev, rimage_lv))
+ return_0;
+
+ if (slog_core && slog) {
+ log_error("Either slog or corelog must be used.");
+ return 0;
+ }
+
+ if (slog && !_replicator_device_add_slog(rdev, slog))
+ return_0;
+
+ return 1;
+}
+
+int replicator_site_remove_device(struct replicator_device *rdev)
+{
+ dm_list_del(&rdev->list);
+
+ return 1;
+}
-#if 0
/*
- * Create new LV to pretend the original LV
- * this target will have a 'replicator' segment
+ * Create new layered LV over the original LV
+ * this target will have a 'replicator-dev' segment
*/
-int lv_add_replicator(struct logical_volume *origin, const char *rep_suffix)
+int lv_add_replicator_dev(struct logical_volume *replicator,
+ struct logical_volume *lv)
{
- struct logical_volume *rep_lv;
- char *name;
- size_t slen;
+ const struct segment_type *segtype;
+ struct logical_volume *rimage_lv;
+ 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 (!(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(lv->vg->cmd, "replicator-dev")))
+ return_0;
+
+ 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;
}
- 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 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++;
}
- if (!(rep_lv = lv_create_empty(name, &origin->lvid,
- LVM_READ | LVM_WRITE | VISIBLE_LV,
- ALLOC_INHERIT, origin->vg)))
- return_0;
+ first_seg(replicator)->rdevice_index_highest++;
+ dm_list_iterate_items(rsite, &replicator->rsites) {
+ if (rsite->site_index == 0) {
+ if (!(rimage_lv = insert_layer_for_lv(lv->vg->cmd, lv, 0, "_rimage")))
+ return_0;
+
+ seg = first_seg(lv);
+ seg->segtype = segtype; /* switch to replicator-dev */
- if (!lv_add_virtual_segment(rep_lv, 0, origin->le_count,
- get_segtype_from_string(origin->vg->cmd,
- "error")))
+ if (!replicator_add_replicator_dev(replicator, seg))
+ return_0;
+
+ if (!replicator_site_add_device(rsite, seg, rimage_lv->name,
+ rimage_lv, 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;
+}
+
+int lv_remove_replicator_dev(struct logical_volume *lv)
+{
+ struct replicator_site *rsite;
+ struct replicator_device *rdev, *trdev;
+ struct logical_volume *replicator = first_seg(lv)->replicator;
+ uint64_t device_index = lv->rdevice->device_index;
+
+ dm_list_iterate_items(rsite, &replicator->rsites) {
+ if (rsite->site_index == 0)
+ continue;
+ dm_list_iterate_items_safe(rdev, trdev, &rsite->rdevices) {
+ if (rdev->device_index != device_index)
+ continue;
+ if (!_replicator_device_remove_slog(rdev))
+ return_0;
+ dm_list_del(&rdev->list);
+ }
+ }
+
+ if (!replicator_remove_replicator_dev(first_seg(lv)))
return_0;
- rep_lv->status |= VIRTUAL;
return 1;
}
-int lv_remove_replicator(struct logical_volume *lv)
+int lv_add_replicator_site(struct logical_volume *replicator,
+ const struct replicator_site *rsite)
{
+ struct replicator_site *nrsite;
+
+ if (find_site_in_replicator(replicator, rsite->name)) {
+ log_error("Site %s already exists.", rsite->name);
+ return 0;
+ }
+
+ if (!(nrsite = replicator_add_site(replicator, rsite->name)))
+ return_0;
+
+ 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;
+ }
+
+ 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;
+
return 1;
}
-#endif
+
+int lv_remove_replicator_site(struct logical_volume *replicator,
+ const char *site_name)
+{
+ log_error("FIXME remove replicator site.");
+ return 0;
+}
+
+struct replicator_site *find_site_in_replicator(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;
+}
/*
* Check all replicator structures:
@@ -266,7 +478,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)) {
@@ -356,8 +568,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 +579,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 +602,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 +623,9 @@ int check_replicator_segment(const struct lv_segment *rseg)
lv->name, rsite->name);
r = 0;
}
- if (rdev->device_index > rseg->rdevice_index_highest) {
+ if (rdev->device_index >= rseg->rdevice_index_highest) {
log_error("Device index %" PRIu64
- " > %" PRIu64 " (too high) "
+ " >= %" PRIu64 " (too high) "
"for replicator site %s/%s.",
rdev->device_index,
rseg->rdevice_index_highest,
@@ -411,7 +644,7 @@ int check_replicator_segment(const struct lv_segment *rseg)
*/
int lv_is_active_replicator_dev(const struct logical_volume *lv)
{
- return ((lv->status & REPLICATOR) &&
+ return (lv_is_replicator_dev(lv) &&
lv->rdevice &&
lv->rdevice->rsite &&
lv->rdevice->rsite->state == REPLICATOR_STATE_ACTIVE);
@@ -442,7 +675,8 @@ int lv_is_replicator_dev(const struct logical_volume *lv)
*/
int lv_is_rimage(const struct logical_volume *lv)
{
- return (lv->rdevice && lv->rdevice->lv == lv);
+ return (!lv_is_replicator_dev(lv) &&
+ (lv->rdevice && lv->rdevice->lv == lv));
}
/**
@@ -646,13 +880,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 +925,445 @@ 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;
+}
+
+int vg_prepare_replicator(struct volume_group *vg,
+ const struct lvcreate_params *lp)
+{
+ struct logical_volume *replicator;
+ struct replicator_device *rdev;
+ struct replicator_site *rsite;
+ unsigned site_index;
+ uint64_t device_index;
+
+ 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;
+ }
+ }
+ }
+ }
+
+ /* For site creation - no new LV will created */
+ if (lp->rsite.name && strlen(lp->replicator)) {
+ if (!(replicator = find_lv(vg, lp->replicator))) {
+ log_error("Replicator %s does not exists",
+ lp->replicator);
+ 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)
+{
+ 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 (!(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;
+ }
+
+ if (!(rlog_lv = insert_layer_for_lv(replicator->vg->cmd,
+ replicator, 0, "_rlog"))) {
+ log_error("Failed to insert replicator _rlog");
+ 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;
+
+ replicator_add_replicator_dev(replicator, NULL);
+
+ if (!replicator_add_rlog(repseg, rlog_lv))
+ return_0;
+
+ return 1;
+}
--
1.7.1
^ permalink raw reply related [flat|nested] 13+ messages in thread* [PATCH 11/12] Replicator: replicator.c changes
2010-06-29 16:26 [PATCH 00/12] Replicator 100629 Zdenek Kabelac
` (9 preceding siblings ...)
2010-06-29 16:26 ` [PATCH 10/12] Replicator: replicator_manip changes Zdenek Kabelac
@ 2010-06-29 16:26 ` Zdenek Kabelac
2010-06-29 16:26 ` [PATCH 12/12] Replicator: man pages for lvchange.8 Zdenek Kabelac
11 siblings, 0 replies; 13+ messages in thread
From: Zdenek Kabelac @ 2010-06-29 16:26 UTC (permalink / raw)
To: lvm-devel
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).
Signed-off-by: Zdenek Kabelac <zkabelac@redhat.com>
---
lib/replicator/replicator.c | 124 ++++++++++++++++---------------------------
1 files changed, 46 insertions(+), 78 deletions(-)
diff --git a/lib/replicator/replicator.c b/lib/replicator/replicator.c
index 6f09321..b62b7fc 100644
--- a/lib/replicator/replicator.c
+++ b/lib/replicator/replicator.c
@@ -138,27 +138,14 @@ static dm_replicator_mode_t _get_op_mode(const struct config_node *sn,
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 = find_site_in_replicator(replicator, key)))
+ return rsite;
- if (!(rsite = dm_pool_zalloc(mem, sizeof(*rsite))))
- return_NULL;
-
- if (!(rsite->name = dm_pool_strdup(mem, key)))
- return_NULL;
-
- rsite->replicator = replicator;
- dm_list_init(&rsite->rdevices);
- dm_list_add(&replicator->rsites, &rsite->list);
-
- return rsite;
+ return replicator_add_site(replicator, key);
}
-
/* Parse replicator site element */
static int _add_site(struct lv_segment *seg,
const char *key,
@@ -267,6 +254,7 @@ static int _replicator_text_import(struct lv_segment *seg,
if (!_add_site(seg, sn->key, sn->child))
return_0;
}
+
return 1;
}
@@ -277,7 +265,7 @@ static int _replicator_text_export(const struct lv_segment *seg,
struct replicator_site *rsite;
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);
@@ -445,13 +433,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_lv = 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 +447,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_lv = 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))))
+ if (!replicator_site_add_device(rsite, seg, lv_name, rimage_lv,
+ slog_core, slog, devidx))
return_0;
- if (!(rdev->name = dm_pool_strdup(mem, dev_str)))
- return_0;
-
- rdev->replicator_dev = seg;
- rdev->rsite = rsite;
- rdev->device_index = devidx;
-
- if (!seg->lv->rdevice) {
- if (!replicator_dev_add_rimage(rdev, lv))
- return SEG_LOG_ERROR("LV inconsistency found in");
- seg->lv->rdevice = rdev;
- } else {
- if (!slog_str ||
- !(rdev->slog_name = dm_pool_strdup(mem, slog_str)))
- return_0;
-
- if (!replicator_dev_add_slog(rdev, slog_lv))
- return SEG_LOG_ERROR("Sync log inconsistency found in");
- }
-
- dm_list_add(&rsite->rdevices, &rdev->list);// linked site list
-
return 1;
}
@@ -553,9 +522,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 +552,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 +593,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 +610,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 +636,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 +649,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 +734,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;
--
1.7.1
^ permalink raw reply related [flat|nested] 13+ messages in thread* [PATCH 12/12] Replicator: man pages for lvchange.8
2010-06-29 16:26 [PATCH 00/12] Replicator 100629 Zdenek Kabelac
` (10 preceding siblings ...)
2010-06-29 16:26 ` [PATCH 11/12] Replicator: replicator.c changes Zdenek Kabelac
@ 2010-06-29 16:26 ` Zdenek Kabelac
11 siblings, 0 replies; 13+ messages in thread
From: Zdenek Kabelac @ 2010-06-29 16:26 UTC (permalink / raw)
To: lvm-devel
Signed-off-by: Zdenek Kabelac <zkabelac@redhat.com>
---
man/lvchange.8.in | 37 +++++++++++++++++++++++++++++++++++++
1 files changed, 37 insertions(+), 0 deletions(-)
diff --git a/man/lvchange.8.in b/man/lvchange.8.in
index e269802..33196c9 100644
--- a/man/lvchange.8.in
+++ b/man/lvchange.8.in
@@ -7,6 +7,12 @@ 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]
+{[\-\-fallbehinddata Size[bBsSkKmMgGtTpPeE]] |
+[\-\-fallbehindios IOS] |
+[\-\-fallbehindtimeout sec]}
+[\-\-sitemode [sync|warn|stall|drop|fail]
+[\-\-remotevg RemoteVolumeGroupName]]
[\-\-resync]
[\-h|\-?|\-\-help]
[\-\-ignorelockingfailure]
@@ -112,10 +118,41 @@ 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
+.I \-\-remotevg
+Selects remote volume group for remote site that contains logical volumes
+with same names for replication as the volume group for site. Local site
+for replicator is assumed if remotevolumegroup is not specified.
+.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 site Berlin for LV vg00/L1 as active.
+
.SH SEE ALSO
.BR lvm (8),
.BR lvcreate (8),
--
1.7.1
^ permalink raw reply related [flat|nested] 13+ messages in thread