summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHeinz Mauelshagen <heinzm@redhat.com>2017-02-06 22:09:26 +0100
committerHeinz Mauelshagen <heinzm@redhat.com>2017-02-07 01:01:19 +0100
commitcfb6ef654d3d1f1dd02569a1d5bd2fc252ae2494 (patch)
tree94673c15794f2ac6436a27fd7e9e360712c95d76
parent51d03acb1c910a65ff05a0a339ed6a4ff957c0db (diff)
downloadlvm2-cfb6ef654d3d1f1dd02569a1d5bd2fc252ae2494.tar.gz
lvconvert: add support to change RAID region size
Add: - support to change region size of existing RaidLVs (all RAID LV types but raid0/raid0_meta) - lvconvert-raid-regionsize.sh with test variations for different RAID types and region sizes Resolves: rhbz1392947
-rw-r--r--WHATS_NEW1
-rw-r--r--lib/metadata/raid_manip.c105
-rw-r--r--test/shell/lvconvert-raid-regionsize.sh90
-rw-r--r--tools/lvconvert.c4
4 files changed, 198 insertions, 2 deletions
diff --git a/WHATS_NEW b/WHATS_NEW
index cbe6c059d..c6994ca06 100644
--- a/WHATS_NEW
+++ b/WHATS_NEW
@@ -1,5 +1,6 @@
Version 2.02.169 -
=====================================
+ Support region size changes on existing RaidLVs
Avoid parallel usage of cpg_mcast_joined() in clvmd with corosync.
Support raid6_{ls,rs,la,ra}_6 segment types and conversions from/to it.
Support raid6_n_6 segment type and conversions from/to it.
diff --git a/lib/metadata/raid_manip.c b/lib/metadata/raid_manip.c
index 736e2ee8b..9b9f5f338 100644
--- a/lib/metadata/raid_manip.c
+++ b/lib/metadata/raid_manip.c
@@ -746,6 +746,27 @@ static int _alloc_image_components(struct logical_volume *lv,
}
/*
+ * HM Helper:
+ *
+ * Calculate absolute amount of metadata device extents based
+ * on @rimage_extents, @region_size and @extent_size.
+ */
+static uint32_t _raid_rmeta_extents(struct cmd_context *cmd, uint32_t rimage_extents,
+ uint32_t region_size, uint32_t extent_size)
+{
+ uint64_t bytes, regions, sectors;
+
+ region_size = region_size ?: get_default_region_size(cmd);
+ regions = (uint64_t) rimage_extents * extent_size / region_size;
+
+ /* raid and bitmap superblocks + region bytes */
+ bytes = 2 * 4096 + dm_div_up(regions, 8);
+ sectors = dm_div_up(bytes, 512);
+
+ return dm_div_up(sectors, extent_size);
+}
+
+/*
* _alloc_rmeta_for_lv
* @lv
*
@@ -3847,6 +3868,86 @@ replaced:
return 1;
}
+/*
+ * HM Helper:
+ *
+ * Change region size on raid @lv to @region_size if
+ * different from current region_size and adjusted region size
+ */
+static int _region_size_change_requested(struct logical_volume *lv, int yes, uint32_t region_size)
+{
+ uint32_t old_region_size;
+ const char *seg_region_size_str;
+ struct lv_segment *seg = first_seg(lv);
+
+ /* Caller should ensure this */
+ if (!region_size)
+ return_0;
+
+ /* CLI validation prvides the check but be caucious... */
+ if (seg_is_any_raid0(seg))
+ return_0;
+
+ if (region_size == seg->region_size) {
+ log_warn("Region size wouldn't change on %s LV %s.",
+ lvseg_name(seg), display_lvname(lv));
+ return 0;
+ }
+
+ if (region_size * 8 > lv->size) {
+ log_error("Requested region size too large for LV %s size %s.",
+ display_lvname(lv), display_size(lv->vg->cmd, lv->size));
+ return 0;
+ }
+
+ if (region_size < seg->stripe_size) {
+ log_error("Region size for LV %s is smaller than stripe size.",
+ display_lvname(lv));
+ return 0;
+ }
+
+ if (!_raid_in_sync(lv)) {
+ log_error("Unable to change region size on %s LV %s while it is not in-sync.",
+ lvseg_name(seg), display_lvname(lv));
+ return 0;
+ }
+
+ old_region_size = seg->region_size;
+ seg->region_size = region_size;
+ seg_region_size_str = display_size(lv->vg->cmd, seg->region_size);
+ _check_and_adjust_region_size(lv);
+
+ if (seg->region_size == old_region_size) {
+ log_warn("Region size on %s did not change due to adjustment.",
+ display_lvname(lv));
+ return 1;
+ }
+
+ if (!yes && yes_no_prompt("Do you really want to change the region_size %s of LV %s to %s? [y/n]: ",
+ display_size(lv->vg->cmd, old_region_size),
+ display_lvname(lv), seg_region_size_str) == 'n') {
+ log_error("Logical volume %s NOT converted", display_lvname(lv));
+ return 0;
+ }
+ if (sigint_caught())
+ return_0;
+
+ /* Check for new region size causing bitmap to still fit metadata image LV */
+ if (seg->meta_areas && seg_metatype(seg, 0) == AREA_LV && seg_metalv(seg, 0)->le_count <
+ _raid_rmeta_extents(lv->vg->cmd, lv->le_count, seg->region_size, lv->vg->extent_size)) {
+ log_error("Region size %s on %s is too small for metadata LV size.",
+ seg_region_size_str, display_lvname(lv));
+ return 0;
+ }
+
+ if (!lv_update_and_reload_origin(lv))
+ return_0;
+
+ log_warn("Changed region size on RAID LV %s to %s.",
+ display_lvname(lv), seg_region_size_str);
+ return 1;
+}
+
/* Check allowed conversion from seg_from to *segtype_to */
static int _conversion_options_allowed(const struct lv_segment *seg_from,
const struct segment_type **segtype_to,
@@ -3923,6 +4024,10 @@ int lv_raid_convert(struct logical_volume *lv,
if (segtype_is_raid(new_segtype) && !_check_max_raid_devices(new_image_count))
return_0;
+ /* Change RAID region size */
+ if (new_region_size && new_region_size != seg->region_size)
+ return _region_size_change_requested(lv, yes, new_region_size);
+
/*
* Check acceptible options mirrors, region_size,
* stripes and/or stripe_size have been provided.
diff --git a/test/shell/lvconvert-raid-regionsize.sh b/test/shell/lvconvert-raid-regionsize.sh
new file mode 100644
index 000000000..4f0e90da7
--- /dev/null
+++ b/test/shell/lvconvert-raid-regionsize.sh
@@ -0,0 +1,90 @@
+#!/bin/sh
+# Copyright (C) 2017 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+SKIP_WITH_LVMLOCKD=1
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux have_raid 1 9 0 || skip
+
+aux prepare_vg 6
+
+function _test_regionsize
+{
+ local type=$1
+ local regionsize=$2
+ local regionsize_str=$3
+ local vg=$4
+ local lv=$5
+
+ lvconvert --type $type --yes -R $regionsize $vg/$lv
+ [ $? -ne 0 ] && return 1
+ check lv_field $vg/$lv regionsize "$regionsize_str"
+ fsck -fn /dev/mapper/$vg-$lv
+}
+
+function _test_regionsizes
+{
+ # FIXME: have to provide raid type or region size ain't set until cli validation merged
+ local type=$1
+
+ # Test RAID regionsize changes
+ _test_regionsize $type 128K "128.00k" $vg $lv1
+ _test_regionsize $type 256K "256.00k" $vg $lv1
+ not _test_regionsize $type 1K "1.00k" $vg $lv1
+ _test_regionsize $type 1m "1.00m" $vg $lv1
+ not _test_regionsize $type 1G "1.00g" $vg $lv1
+ not _test_regionsize $type 16K "16.00k" $vg $lv1
+}
+
+# Create 3-way raid1
+lvcreate --yes -aey --type raid1 -m 2 -R64K -L 64M -n $lv1 $vg
+check lv_field $vg/$lv1 segtype "raid1"
+check lv_field $vg/$lv1 stripes 3
+check lv_field $vg/$lv1 regionsize "64.00k"
+echo y | mkfs -t ext4 /dev/mapper/$vg-$lv1
+aux wait_for_sync $vg $lv1
+fsck -fn /dev/mapper/$vg-$lv1
+
+_test_regionsizes raid1
+
+# Clean up
+lvremove --yes $vg
+
+# Create 5-way raid6
+lvcreate --yes -aey --type raid6 -i 3 --stripesize 128K -R 256K -L 64M -n $lv1 $vg
+check lv_field $vg/$lv1 segtype "raid6"
+check lv_field $vg/$lv1 stripes 5
+check lv_field $vg/$lv1 stripesize "128.00k"
+check lv_field $vg/$lv1 regionsize "256.00k"
+echo y | mkfs -t ext4 /dev/mapper/$vg-$lv1
+aux wait_for_sync $vg $lv1
+fsck -fn /dev/mapper/$vg-$lv1
+
+_test_regionsizes raid6
+
+# Clean up
+lvremove --yes $vg
+
+# Create 6-way raid01
+lvcreate --yes -aey --type raid10 -i 3 -m 1 --stripesize 128K -R 256K -L 64M -n $lv1 $vg
+check lv_field $vg/$lv1 segtype "raid10"
+check lv_field $vg/$lv1 stripes 6
+check lv_field $vg/$lv1 stripesize "128.00k"
+check lv_field $vg/$lv1 regionsize "256.00k"
+echo y | mkfs -t ext4 /dev/mapper/$vg-$lv1
+aux wait_for_sync $vg $lv1
+fsck -fn /dev/mapper/$vg-$lv1
+
+_test_regionsizes raid10
+
+vgremove -ff $vg
diff --git a/tools/lvconvert.c b/tools/lvconvert.c
index ba8396f9a..32e04d6f5 100644
--- a/tools/lvconvert.c
+++ b/tools/lvconvert.c
@@ -2012,13 +2012,13 @@ static int _lvconvert_raid(struct logical_volume *lv, struct lvconvert_params *l
return 1;
}
goto try_new_takeover_or_reshape;
- } else if (!lp->repair && !lp->replace && (!*lp->type_str || seg->segtype == lp->segtype)) {
+ } else if (!lp->repair && !lp->replace && !arg_is_set(cmd, regionsize_ARG) && (!*lp->type_str || seg->segtype == lp->segtype)) {
log_error("Conversion operation not yet supported.");
return 0;
}
if ((seg_is_linear(seg) || seg_is_striped(seg) || seg_is_mirrored(seg) || lv_is_raid(lv)) &&
- (lp->type_str && lp->type_str[0])) {
+ ((lp->type_str && lp->type_str[0]) || arg_is_set(cmd, regionsize_ARG))) {
/* Activation is required later which precludes existing supported raid0 segment */
if ((seg_is_any_raid0(seg) || segtype_is_any_raid0(lp->segtype)) &&
!(lp->target_attr & RAID_FEATURE_RAID0)) {