[lvm-devel] [PATCH 2 of 2] LVM: use new split capability
Jonathan Brassow
jbrassow at redhat.com
Fri Oct 30 21:50:56 UTC 2009
Patch name: lvm-use-new-split-capability.patch
Percolate the ability split off a leg up to the user.
The following command line interface is enforced:
prompt> lvconvert --splitmirror <n> -n <name> <VG>/<LV>
where 'n' is the number of legs to split off, and
where 'name' is the name of the newly split off logical volume.
It can be seen that '--splitmirror <n>' is exactly the same
as '--mirrors -<n>' (note the minus sign), except there is the
additional notion to keep the image being detached from the
mirror instead of just throwing it away. So, we _could_ have
a '--keep' argument or something that could be used in
conjunction with '--mirrors' to denote the fact that we wish
to keep the image being detached. It has been suggested that
we could have two ways of specifying this action. I have
not implemented that here. I am strictly choosing '--splitmirror'
and purposefully choosing not to have something additional
for '--mirrors'. I think this prevents confusion. The
additional argument for '--mirrors' will have to come by way
of another patch.
Also, I have chosen to make the '-n <name>' argument manditory.
Perhaps in the future when we decide on a useful default name
we can relax this enforcement. There is no reason to withhold
the capability because we haven't formed a concensous on what
a default name should be. [Perhaps we will make a better
informed decision on that when we begin to implement
'--track_deltas'.]
Signed-off-by: Jonathan Brassow <jbrassow at redhat.com>
Index: LVM2/lib/metadata/mirror.c
===================================================================
--- LVM2.orig/lib/metadata/mirror.c
+++ LVM2/lib/metadata/mirror.c
@@ -541,24 +541,36 @@ static int _remove_mirror_images(struct
for (m = new_area_count; m < mirrored_seg->area_count; m++) {
seg_lv(mirrored_seg, m)->status &= ~MIRROR_IMAGE;
lv_set_visible(seg_lv(mirrored_seg, m));
- if (!split) {
- lvl = dm_pool_alloc(lv->vg->cmd->mem, sizeof(*lvl));
- if (!lvl) {
- log_error("lv_list alloc failed");
+
+ if (split) {
+ remove_seg_from_segs_using_this_lv(seg_lv(mirrored_seg, m),
+ mirrored_seg);
+
+ sub_lv = seg_lv(mirrored_seg, m);
+ sub_lv->name = dm_pool_strdup(lv->vg->cmd->mem, split);
+ if (!sub_lv->name) {
+ log_error("Unable to rename newly split LV");
return 0;
}
- lvl->lv = seg_lv(mirrored_seg, m);
- dm_list_add(&tmp_orphan_lvs, &lvl->list);
- release_lv_segment_area(mirrored_seg, m,
- mirrored_seg->area_len);
- continue;
+
+ /*
+ * By putting this 'break' here, it should be
+ * obvious that only one leg can be split off
+ * with the code as written - consistent with
+ * the level of functionality currently offered.
+ */
+ break;
}
- remove_seg_from_segs_using_this_lv(seg_lv(mirrored_seg, m),
- mirrored_seg);
- if (!lv_rename(lv->vg->cmd, seg_lv(mirrored_seg, m), split)) {
- log_error("Unable to rename newly split LV");
+
+ lvl = dm_pool_alloc(lv->vg->cmd->mem, sizeof(*lvl));
+ if (!lvl) {
+ log_error("lv_list alloc failed");
return 0;
}
+ lvl->lv = seg_lv(mirrored_seg, m);
+ dm_list_add(&tmp_orphan_lvs, &lvl->list);
+ release_lv_segment_area(mirrored_seg, m,
+ mirrored_seg->area_len);
}
mirrored_seg->area_count = new_area_count;
@@ -1611,6 +1623,42 @@ int lv_add_mirrors(struct cmd_context *c
return 0;
}
+int lv_split_mirror_images(struct logical_volume *lv, const char *split_lv_name,
+ uint32_t split_count, struct dm_list *removable_pvs)
+{
+ int r;
+
+ /*
+ * Right now, we only allow the user to split a single
+ * leg off at a time. In the future, we might allow a
+ * 4-way mirror to be split into 2 2-way mirrors, but
+ * not right now.
+ */
+ if (split_count != 1) {
+ log_error("Unable to split more than one leg from a mirror.");
+ return_0;
+ }
+
+ /* Can't split a mirror that is not in-sync... unless force? */
+ if (!_mirrored_lv_in_sync(lv)) {
+ log_error("Unable to split mirror that is not in-sync.");
+ return_0;
+ }
+
+ /*
+ * If we were going to generate a default name, we would
+ * do it here, but I am not interested in default names.
+ */
+ r = _remove_mirror_images(lv, split_count,
+ removable_pvs, 0, 0,
+ split_lv_name, NULL);
+ if (!r)
+ return 0;
+
+ /* Rename split leg here? */
+ return 1;
+}
+
/*
* Generic interface for removing mirror and/or mirror log.
* 'mirror' is the number of mirrors to be removed.
Index: LVM2/tools/args.h
===================================================================
--- LVM2.orig/tools/args.h
+++ LVM2/tools/args.h
@@ -50,6 +50,7 @@ arg(nosync_ARG, '\0', "nosync", NULL, 0)
arg(resync_ARG, '\0', "resync", NULL, 0)
arg(corelog_ARG, '\0', "corelog", NULL, 0)
arg(mirrorlog_ARG, '\0', "mirrorlog", string_arg, 0)
+arg(splitmirror_ARG, '\0', "splitmirror", int_arg, 0)
arg(repair_ARG, '\0', "repair", NULL, 0)
arg(use_policies_ARG, '\0', "use-policies", NULL, 0)
arg(monitor_ARG, '\0', "monitor", yes_no_arg, 0)
Index: LVM2/tools/commands.h
===================================================================
--- LVM2.orig/tools/commands.h
+++ LVM2/tools/commands.h
@@ -96,6 +96,7 @@ xx(lvconvert,
0,
"lvconvert "
"[-m|--mirrors Mirrors [{--mirrorlog {disk|core|redundant}|--corelog}]]\n"
+ "[--splitmirror Count -n SplitLogicalVolumeName]\n"
"\t[--repair [--use-policies]]\n"
"\t[-R|--regionsize MirrorLogRegionSize]\n"
"\t[--alloc AllocationPolicy]\n"
@@ -122,8 +123,9 @@ xx(lvconvert,
"\tOriginalLogicalVolume[Path] SnapshotLogicalVolume[Path]\n",
alloc_ARG, background_ARG, chunksize_ARG, corelog_ARG, interval_ARG,
- mirrorlog_ARG, mirrors_ARG, noudevsync_ARG, regionsize_ARG, repair_ARG,
- snapshot_ARG, test_ARG, use_policies_ARG, yes_ARG, force_ARG, zero_ARG)
+ splitmirror_ARG, name_ARG, mirrorlog_ARG, mirrors_ARG, noudevsync_ARG,
+ regionsize_ARG, repair_ARG, snapshot_ARG, test_ARG, use_policies_ARG,
+ yes_ARG, force_ARG, zero_ARG)
xx(lvcreate,
"Create a logical volume",
Index: LVM2/tools/lvconvert.c
===================================================================
--- LVM2.orig/tools/lvconvert.c
+++ LVM2/tools/lvconvert.c
@@ -16,12 +16,16 @@
#include "polldaemon.h"
#include "lv_alloc.h"
+#define MIRROR_FLAG_KEEP_IMAGES 0x1
+#define MIRROR_FLAG_TRACK_DELTAS 0x2
+
struct lvconvert_params {
int snapshot;
int zero;
const char *origin;
const char *lv_name;
+ const char *lv_split_name;
const char *lv_name_full;
const char *vg_name;
int wait_completion;
@@ -30,8 +34,10 @@ struct lvconvert_params {
uint32_t chunk_size;
uint32_t region_size;
+ int track_deltas;
uint32_t mirrors;
sign_t mirrors_sign;
+ uint32_t mirror_flags;
struct segment_type *segtype;
@@ -124,14 +130,53 @@ static int _read_params(struct lvconvert
if (arg_count(cmd, snapshot_ARG))
lp->snapshot = 1;
+ if (arg_count(cmd, splitmirror_ARG) && arg_count(cmd, mirrors_ARG)) {
+ log_error("--mirrors (-m) argument and --splitmirror arguments"
+ " are mutually exclusive");
+ return 0;
+ }
+
+ /*
+ * The --splitmirror argument is essentially the inverse of
+ * the --mirrors argument with the additional intention of keeping
+ * the leg that is split off.
+ */
+ if (arg_count(cmd, splitmirror_ARG)) {
+ if (!arg_count(cmd, name_ARG)) {
+ log_error("The split off mirror image requires a name");
+ return 0;
+ }
+
+ lp->lv_split_name = arg_value(cmd, name_ARG);
+ if (!apply_lvname_restrictions(lp->lv_split_name))
+ return_0;
+
+ lp->mirror_flags |= MIRROR_FLAG_KEEP_IMAGES;
+ if (arg_sign_value(cmd, mirrors_ARG, 0) == SIGN_MINUS) {
+ log_error("Argument to --splitmirror"
+ " cannot be negative");
+ return 0;
+ }
+ lp->mirrors = arg_uint_value(cmd, splitmirror_ARG, 0);
+ lp->mirrors_sign = SIGN_MINUS;
+ } else if (arg_count(cmd, name_ARG)) {
+ log_error("The 'name' argument is only valid"
+ " with --splitmirror");
+ return 0;
+ }
+
if (arg_count(cmd, mirrors_ARG)) {
+ /*
+ * We could also add an argument that would compliment the
+ * meaning of --mirrors to also keep removed legs, but I'm
+ * not going to do that.
+ */
lp->mirrors = arg_uint_value(cmd, mirrors_ARG, 0);
lp->mirrors_sign = arg_sign_value(cmd, mirrors_ARG, 0);
}
- lp->alloc = ALLOC_INHERIT;
if (arg_count(cmd, alloc_ARG))
- lp->alloc = arg_uint_value(cmd, alloc_ARG, lp->alloc);
+ lp->alloc = arg_uint_value(cmd, alloc_ARG, ALLOC_INHERIT);
if (lp->snapshot) {
if (arg_count(cmd, regionsize_ARG)) {
@@ -545,7 +590,7 @@ static int _lvconvert_mirrors(struct cmd
/* If called with no argument, try collapsing the resync layers */
if (!arg_count(cmd, mirrors_ARG) && !arg_count(cmd, mirrorlog_ARG) &&
!arg_count(cmd, corelog_ARG) && !arg_count(cmd, regionsize_ARG) &&
- !repair) {
+ !arg_count(cmd, splitmirror_ARG) && !repair) {
if (find_temporary_mirror(lv) || (lv->status & CONVERTING))
lp->need_polling = 1;
return 1;
@@ -564,7 +609,7 @@ static int _lvconvert_mirrors(struct cmd
* count to remain the same. They may be changing
* the logging type.
*/
- if (!arg_count(cmd, mirrors_ARG))
+ if (!arg_count(cmd, mirrors_ARG) && !arg_count(cmd, splitmirror_ARG))
lp->mirrors = existing_mirrors;
else if (lp->mirrors_sign == SIGN_PLUS)
lp->mirrors = existing_mirrors + lp->mirrors;
@@ -681,10 +726,17 @@ static int _lvconvert_mirrors(struct cmd
/* Reduce number of mirrors */
if (repair || lp->pv_count)
remove_pvs = lp->pvh;
- if (!lv_remove_mirrors(cmd, lv, existing_mirrors - lp->mirrors,
- (!log_count || lp->mirrors == 1) ? 1U : 0U,
- remove_pvs, 0))
+
+ if (lp->mirror_flags & MIRROR_FLAG_KEEP_IMAGES) {
+ if (!lv_split_mirror_images(lv, lp->lv_split_name,
+ existing_mirrors - lp->mirrors,
+ remove_pvs))
+ return 0;
+ } else if (!lv_remove_mirrors(cmd, lv, existing_mirrors - lp->mirrors,
+ (!log_count || lp->mirrors == 1) ? 1U : 0U,
+ remove_pvs, 0))
return_0;
+
if (lp->mirrors > 1 &&
!_lv_update_log_type(cmd, lp, lv, log_count))
return_0;
Index: LVM2/lib/metadata/metadata-exported.h
===================================================================
--- LVM2.orig/lib/metadata/metadata-exported.h
+++ LVM2/lib/metadata/metadata-exported.h
@@ -651,6 +651,8 @@ int lv_add_mirrors(struct cmd_context *c
uint32_t mirrors, uint32_t stripes,
uint32_t region_size, uint32_t log_count,
struct dm_list *pvs, alloc_policy_t alloc, uint32_t flags);
+int lv_split_mirror_images(struct logical_volume *lv, const char *split_lv_name,
+ uint32_t split_count, struct dm_list *removable_pvs);
int lv_remove_mirrors(struct cmd_context *cmd, struct logical_volume *lv,
uint32_t mirrors, uint32_t log_count,
struct dm_list *pvs, uint32_t status_mask);
Index: LVM2/man/lvconvert.8.in
===================================================================
--- LVM2.orig/man/lvconvert.8.in
+++ LVM2/man/lvconvert.8.in
@@ -16,6 +16,13 @@ LogicalVolume[Path] [PhysicalVolume[Path
.br
.B lvconvert
+\-\-splitmirror Images \-n SplitLogicalVolumeName
+.br
+MirrorLogicalVolume[Path] [SplittablePhysicalVolume[Path][:PE[-PE]]...]
+.br
+
+.br
+.B lvconvert
\-s|\-\-snapshot [\-c|\-\-chunksize ChunkSize]
[\-h|\-?|\-\-help]
[\-\-noudevsync]
@@ -47,7 +54,7 @@ the freed extents come first from the sp
.SH OPTIONS
See \fBlvm\fP for common options.
.br
-Exactly one of \-\-mirrors, \-\-repair or \-\-snapshot arguments required.
+Exactly one of \-\-splitmirror, \-\-mirrors, \-\-repair or \-\-snapshot arguments required.
.br
.TP
.I \-m, \-\-mirrors Mirrors
@@ -86,16 +93,22 @@ process will not wait for notification f
It will continue irrespective of any possible udev processing
in the background. You should only use this if udev is not running
or has rules that ignore the devices LVM2 creates.
+.br
+
+
.TP
-.I \-\-repair
-Repair a mirror after suffering a disk failure. The mirror will be brought back
-into a consistent state. By default, the original number of mirrors will be
-restored if possible. Specify \-y on the command line to skip the prompts.
-Use \-f if you do not want any replacement. Additionally, you may use
-\-\-use-policies to use the device replacement policy specified in lvm.conf,
-viz. activation/mirror_log_fault_policy or
-activation/mirror_device_fault_policy.
+.I \-\-splitmirror Images
+Specifies how many images, or legs, of a mirror you wish to split
+off and form a new logical volume from. It is required that a user
+provide a name for the newly split off logical volume, using the \-n
+argument.
+.TP
+.I \-n Name
+The name to apply to a logical volume which has been split off from
+a mirror logical volume.
.br
+
+
.TP
.I \-s, \-\-snapshot
Create a snapshot from existing logical volume using another
@@ -108,6 +121,18 @@ Power of 2 chunk size for the snapshot l
Controls zeroing of the first KB of data in the snapshot.
If the volume is read-only the snapshot will not be zeroed.
.br
+
+
+.TP
+.I \-\-repair
+Repair a mirror after suffering a disk failure. The mirror will be brought back
+into a consistent state. By default, the original number of mirrors will be
+restored if possible. Specify \-y on the command line to skip the prompts.
+Use \-f if you do not want any replacement. Additionally, you may use
+\-\-use-policies to use the device replacement policy specified in lvm.conf,
+viz. activation/mirror_log_fault_policy or
+activation/mirror_device_fault_policy.
+.br
.SH Examples
"lvconvert -m1 vg00/lvol1"
.br
More information about the lvm-devel
mailing list