From f156859bbb8ed8eed4963001ce217e103e66b4e6 Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Jan 17 2017 15:26:05 +0000 Subject: import lvm2-2.02.166-1.el7_3.2 --- diff --git a/SOURCES/lvm2-2_02_167-fix-raid4-coversion-from-striped.patch b/SOURCES/lvm2-2_02_167-fix-raid4-coversion-from-striped.patch new file mode 100644 index 0000000..11dd7db --- /dev/null +++ b/SOURCES/lvm2-2_02_167-fix-raid4-coversion-from-striped.patch @@ -0,0 +1,532 @@ + WHATS_NEW | 2 + + lib/metadata/raid_manip.c | 277 +++++++++++++++++++++++++++++++--- + test/shell/lvconvert-raid-takeover.sh | 53 ++++++- + tools/lvconvert.c | 24 +-- + 4 files changed, 314 insertions(+), 42 deletions(-) + +diff --git a/WHATS_NEW b/WHATS_NEW +index 5cbf4ec..6a0c311 100644 +--- a/WHATS_NEW ++++ b/WHATS_NEW +@@ -1,5 +1,7 @@ + Version 2.02.167 - + ====================================== ++ Add direct striped -> raid4 conversion ++ Fix raid4 parity image pair position on conversions from striped/raid0* + Disable lvconvert of thin pool to raid while active. + + Version 2.02.166 - 26th September 2016 +diff --git a/lib/metadata/raid_manip.c b/lib/metadata/raid_manip.c +index 5fc520e..e5fd195 100644 +--- a/lib/metadata/raid_manip.c ++++ b/lib/metadata/raid_manip.c +@@ -2459,7 +2459,7 @@ static struct lv_segment *_convert_striped_to_raid0(struct logical_volume *lv, + 0 /* chunk_size */, + 0 /* seg->region_size */, 0u /* extents_copied */ , + NULL /* pvmove_source_seg */))) { +- log_error("Failed to allocate new raid0 segement for LV %s.", display_lvname(lv)); ++ log_error("Failed to allocate new raid0 segment for LV %s.", display_lvname(lv)); + return NULL; + } + +@@ -2519,42 +2519,51 @@ static struct possible_takeover_reshape_type _possible_takeover_reshape_types[] + { .current_types = SEG_STRIPED_TARGET, /* linear, i.e. seg->area_count = 1 */ + .possible_types = SEG_RAID1, + .current_areas = 1, +- .options = ALLOW_NONE }, ++ .options = ALLOW_NONE }, /* FIXME: ALLOW_REGION_SIZE */ + { .current_types = SEG_STRIPED_TARGET, /* linear, i.e. seg->area_count = 1 */ + .possible_types = SEG_RAID0|SEG_RAID0_META, + .current_areas = 1, + .options = ALLOW_STRIPE_SIZE }, +- { .current_types = SEG_STRIPED_TARGET, /* striped, i.e. seg->area_count > 1 */ ++ { .current_types = SEG_STRIPED_TARGET, /* striped -> raid0*, i.e. seg->area_count > 1 */ + .possible_types = SEG_RAID0|SEG_RAID0_META, + .current_areas = ~0U, + .options = ALLOW_NONE }, ++ { .current_types = SEG_STRIPED_TARGET, /* striped -> raid4 , i.e. seg->area_count > 1 */ ++ .possible_types = SEG_RAID4, ++ .current_areas = ~0U, ++ .options = ALLOW_NONE }, /* FIXME: ALLOW_REGION_SIZE */ + /* raid0* -> */ + { .current_types = SEG_RAID0|SEG_RAID0_META, /* seg->area_count = 1 */ + .possible_types = SEG_RAID1, + .current_areas = 1, ++ .options = ALLOW_NONE }, /* FIXME: ALLOW_REGION_SIZE */ ++ { .current_types = SEG_RAID0|SEG_RAID0_META, /* raid0* -> striped, i.e. seg->area_count > 1 */ ++ .possible_types = SEG_STRIPED_TARGET, ++ .current_areas = ~0U, + .options = ALLOW_NONE }, +- { .current_types = SEG_RAID0|SEG_RAID0_META, /* seg->area_count > 1 */ +- .possible_types = SEG_RAID4, ++ { .current_types = SEG_RAID0|SEG_RAID0_META, /* raid0* -> raid0*, i.e. seg->area_count > 1 */ ++ .possible_types = SEG_RAID0_META|SEG_RAID0, + .current_areas = ~0U, + .options = ALLOW_NONE }, +- { .current_types = SEG_RAID0|SEG_RAID0_META, /* raid0 striped, i.e. seg->area_count > 0 */ ++ { .current_types = SEG_RAID0|SEG_RAID0_META, /* raid0* -> raid4, i.e. seg->area_count > 1 */ ++ .possible_types = SEG_RAID4, ++ .current_areas = ~0U, ++ .options = ALLOW_NONE }, /* FIXME: ALLOW_REGION_SIZE */ ++ /* raid4 -> -> */ ++ { .current_types = SEG_RAID4, /* raid4 ->striped/raid0*, i.e. seg->area_count > 1 */ + .possible_types = SEG_STRIPED_TARGET|SEG_RAID0|SEG_RAID0_META, + .current_areas = ~0U, + .options = ALLOW_NONE }, +- /* raid1 -> */ ++ /* raid1 -> mirror */ + { .current_types = SEG_RAID1, +- .possible_types = SEG_RAID1|SEG_MIRROR, ++ .possible_types = SEG_MIRROR, + .current_areas = ~0U, +- .options = ALLOW_NONE }, ++ .options = ALLOW_NONE }, /* FIXME: ALLOW_REGION_SIZE */ + /* mirror -> raid1 with arbitrary number of legs */ + { .current_types = SEG_MIRROR, +- .possible_types = SEG_MIRROR|SEG_RAID1, +- .current_areas = ~0U, +- .options = ALLOW_NONE }, +- { .current_types = SEG_RAID4, +- .possible_types = SEG_STRIPED_TARGET|SEG_RAID0|SEG_RAID0_META, ++ .possible_types = SEG_RAID1, + .current_areas = ~0U, +- .options = ALLOW_NONE }, ++ .options = ALLOW_NONE }, /* FIXME: ALLOW_REGION_SIZE */ + + /* END */ + { .current_types = 0 } +@@ -2861,9 +2870,176 @@ static int _raid1_to_mirrored_wrapper(TAKEOVER_FN_ARGS) + allocate_pvs, 1, &removal_lvs); + } + ++/* ++ * HM Helper: (raid0_meta -> raid4) ++ * ++ * To convert raid0_meta to raid4, which involves shifting the ++ * parity device to lv segment area 0 and thus changing MD ++ * array roles, detach the MetaLVs and reload as raid0 in ++ * order to wipe them then reattach and set back to raid0_meta. ++ */ ++static int _clear_meta_lvs(struct logical_volume *lv) ++{ ++ uint32_t s; ++ struct lv_segment *seg = first_seg(lv); ++ struct lv_segment_area *tmp_areas; ++ const struct segment_type *tmp_segtype; ++ struct dm_list meta_lvs; ++ struct lv_list *lvl_array, *lvl; ++ ++ /* Reject non-raid0_meta segment types cautiously */ ++ if (!seg_is_raid0_meta(seg) || ++ !seg->meta_areas) ++ return_0; ++ ++ if (!(lvl_array = dm_pool_alloc(lv->vg->vgmem, seg->area_count * sizeof(*lvl_array)))) ++ return_0; ++ ++ dm_list_init(&meta_lvs); ++ tmp_areas = seg->meta_areas; ++ ++ /* Extract all MetaLVs listing them on @meta_lvs */ ++ log_debug_metadata("Extracting all MetaLVs of %s to activate as raid0", ++ display_lvname(lv)); ++ if (!_extract_image_component_sublist(seg, RAID_META, 0, seg->area_count, &meta_lvs, 0)) ++ return_0; ++ ++ /* Memorize meta areas and segtype to set again after initializing. */ ++ seg->meta_areas = NULL; ++ tmp_segtype = seg->segtype; ++ ++ if (!(seg->segtype = get_segtype_from_flag(lv->vg->cmd, SEG_RAID0)) || ++ !lv_update_and_reload(lv)) ++ return_0; ++ ++ /* ++ * Now deactivate the MetaLVs before clearing, so ++ * that _clear_lvs() will activate them visible. ++ */ ++ log_debug_metadata("Deactivating pulled out MetaLVs of %s before initializing.", ++ display_lvname(lv)); ++ dm_list_iterate_items(lvl, &meta_lvs) ++ if (!deactivate_lv(lv->vg->cmd, lvl->lv)) ++ return_0; ++ ++ log_debug_metadata("Clearing allocated raid0_meta metadata LVs for conversion to raid4"); ++ if (!_clear_lvs(&meta_lvs)) { ++ log_error("Failed to initialize metadata LVs"); ++ return 0; ++ } ++ ++ /* Set memorized meta areas and raid0_meta segtype */ ++ seg->meta_areas = tmp_areas; ++ seg->segtype = tmp_segtype; ++ ++ log_debug_metadata("Adding metadata LVs back into %s", display_lvname(lv)); ++ s = 0; ++ dm_list_iterate_items(lvl, &meta_lvs) { ++ lv_set_hidden(lvl->lv); ++ if (!set_lv_segment_area_lv(seg, s++, lvl->lv, 0, RAID_META)) ++ return 0; ++ } ++ ++ return 1; ++} ++ ++/* ++ * HM Helper: (raid0* <-> raid4) ++ * ++ * Rename SubLVs (pairs) allowing to shift names w/o collisions with active ones. ++ */ ++#define SLV_COUNT 2 ++static int _rename_area_lvs(struct logical_volume *lv, const char *suffix) ++{ ++ uint32_t s; ++ size_t sz = strlen("rimage") + (suffix ? strlen(suffix) : 0) + 1; ++ char *sfx[SLV_COUNT] = { NULL, NULL }; ++ struct lv_segment *seg = first_seg(lv); ++ ++ /* Create _generate_raid_name() suffixes w/ or w/o passed in @suffix */ ++ for (s = 0; s < SLV_COUNT; s++) ++ if (!(sfx[s] = dm_pool_alloc(lv->vg->cmd->mem, sz)) || ++ dm_snprintf(sfx[s], sz, suffix ? "%s%s" : "%s", s ? "rmeta" : "rimage", suffix) < 0) ++ return_0; ++ ++ /* Change names (temporarily) to be able to shift numerical name suffixes */ ++ for (s = 0; s < seg->area_count; s++) { ++ if (!(seg_lv(seg, s)->name = _generate_raid_name(lv, sfx[0], s))) ++ return_0; ++ if (seg->meta_areas && ++ !(seg_metalv(seg, s)->name = _generate_raid_name(lv, sfx[1], s))) ++ return_0; ++ } ++ ++ for (s = 0; s < SLV_COUNT; s++) ++ dm_pool_free(lv->vg->cmd->mem, sfx[s]); ++ ++ return 1; ++} ++ ++/* ++ * HM Helper: (raid0* <-> raid4) ++ * ++ * Switch area LVs in lv segment @seg indexed by @s1 and @s2 ++ */ ++static void _switch_area_lvs(struct lv_segment *seg, uint32_t s1, uint32_t s2) ++{ ++ struct logical_volume *lvt; ++ ++ lvt = seg_lv(seg, s1); ++ seg_lv(seg, s1) = seg_lv(seg, s2); ++ seg_lv(seg, s2) = lvt; ++ ++ /* Be cautious */ ++ if (seg->meta_areas) { ++ lvt = seg_metalv(seg, s1); ++ seg_metalv(seg, s1) = seg_metalv(seg, s2); ++ seg_metalv(seg, s2) = lvt; ++ } ++} ++ ++/* ++ * HM Helper: ++ * ++ * shift range of area LVs in @seg in range [ @s1, @s2 ] up if @s1 < @s2, ++ * else down bubbling the parity SubLVs up/down whilst shifting. ++ */ ++static void _shift_area_lvs(struct lv_segment *seg, uint32_t s1, uint32_t s2) ++{ ++ uint32_t s; ++ ++ if (s1 < s2) ++ /* Forward shift n+1 -> n */ ++ for (s = s1; s < s2; s++) ++ _switch_area_lvs(seg, s, s + 1); ++ else ++ /* Reverse shift n-1 -> n */ ++ for (s = s1; s > s2; s--) ++ _switch_area_lvs(seg, s, s - 1); ++} ++ ++/* ++ * Switch position of first and last area lv within ++ * @lv to move parity SubLVs from end to end. ++ * ++ * Direction depends on segment type raid4 / raid0_meta. ++ */ ++static int _shift_parity_dev(struct lv_segment *seg) ++{ ++ if (seg_is_raid0_meta(seg)) ++ _shift_area_lvs(seg, seg->area_count - 1, 0); ++ else if (seg_is_raid4(seg)) ++ _shift_area_lvs(seg, 0, seg->area_count - 1); ++ else ++ return 0; ++ ++ return 1; ++} ++ + /* raid45 -> raid0* / striped */ + static int _raid456_to_raid0_or_striped_wrapper(TAKEOVER_FN_ARGS) + { ++ int rename_sublvs = 0; + struct lv_segment *seg = first_seg(lv); + struct dm_list removal_lvs; + +@@ -2879,10 +3055,39 @@ static int _raid456_to_raid0_or_striped_wrapper(TAKEOVER_FN_ARGS) + if (!_raid_in_sync(lv)) + return 0; + ++ if (!yes && yes_no_prompt("Are you sure you want to convert \"%s\" LV %s to \"%s\" " ++ "type using all resilience? [y/n]: ", ++ lvseg_name(seg), display_lvname(lv), new_segtype->name) == 'n') { ++ log_error("Logical volume %s NOT converted to \"%s\"", ++ display_lvname(lv), new_segtype->name); ++ return 0; ++ } ++ if (sigint_caught()) ++ return_0; ++ + /* Archive metadata */ + if (!archive(lv->vg)) + return_0; + ++ /* ++ * raid4 (which actually gets mapped to raid5/dedicated first parity disk) ++ * needs shifting of SubLVs to move the parity SubLV pair in the first area ++ * to the last one before conversion to raid0[_meta]/striped to allow for ++ * SubLV removal from the end of the areas arrays. ++ */ ++ if (seg_is_raid4(seg)) { ++ /* Shift parity SubLV pair "PDD..." -> "DD...P" to be able to remove it off the end */ ++ if (!_shift_parity_dev(seg)) ++ return 0; ++ ++ if (segtype_is_any_raid0(new_segtype) && ++ !(rename_sublvs = _rename_area_lvs(lv, "_"))) { ++ log_error("Failed to rename %s LV %s MetaLVs", lvseg_name(seg), display_lvname(lv)); ++ return 0; ++ } ++ ++ } ++ + /* Remove meta and data LVs requested */ + if (!_lv_raid_change_image_count(lv, new_image_count, allocate_pvs, &removal_lvs, 0, 0)) + return 0; +@@ -2902,7 +3107,19 @@ static int _raid456_to_raid0_or_striped_wrapper(TAKEOVER_FN_ARGS) + + seg->region_size = 0; + +- return _lv_update_reload_fns_reset_eliminate_lvs(lv, &removal_lvs); ++ if (!_lv_update_reload_fns_reset_eliminate_lvs(lv, &removal_lvs)) ++ return_0; ++ ++ if (rename_sublvs) { ++ if (!_rename_area_lvs(lv, NULL)) { ++ log_error("Failed to rename %s LV %s MetaLVs", lvseg_name(seg), display_lvname(lv)); ++ return 0; ++ } ++ if (!lv_update_and_reload(lv)) ++ return_0; ++ } ++ ++ return 1; + } + + static int _striped_to_raid0_wrapper(struct logical_volume *lv, +@@ -2930,6 +3147,9 @@ static int _striped_to_raid0_wrapper(struct logical_volume *lv, + static int _striped_or_raid0_to_raid45610_wrapper(TAKEOVER_FN_ARGS) + { + struct lv_segment *seg = first_seg(lv); ++ struct dm_list removal_lvs; ++ ++ dm_list_init(&removal_lvs); + + if (seg_is_raid10(seg)) + return _takeover_unsupported_yet(lv, new_stripes, new_segtype); +@@ -2944,6 +3164,13 @@ static int _striped_or_raid0_to_raid45610_wrapper(TAKEOVER_FN_ARGS) + return 0; + } + ++ /* FIXME: restricted to raid4 for the time being... */ ++ if (!segtype_is_raid4(new_segtype)) { ++ /* Can't convert striped/raid0* to e.g. raid10_offset */ ++ log_error("Can't convert %s to %s", display_lvname(lv), new_segtype->name); ++ return 0; ++ } ++ + /* Archive metadata */ + if (!archive(lv->vg)) + return_0; +@@ -2961,7 +3188,10 @@ static int _striped_or_raid0_to_raid45610_wrapper(TAKEOVER_FN_ARGS) + log_debug_metadata("Adding metadata LVs to %s", display_lvname(lv)); + if (!_raid0_add_or_remove_metadata_lvs(lv, 1 /* update_and_reload */, allocate_pvs, NULL)) + return 0; +- } ++ /* raid0_meta -> raid4 needs clearing of MetaLVs in order to avoid raid disk role cahnge issues in the kernel */ ++ } else if (segtype_is_raid4(new_segtype) && ++ !_clear_meta_lvs(lv)) ++ return 0; + + /* Add the additional component LV pairs */ + log_debug_metadata("Adding %" PRIu32 " component LV pair(s) to %s", new_image_count - lv_raid_image_count(lv), +@@ -2969,8 +3199,9 @@ static int _striped_or_raid0_to_raid45610_wrapper(TAKEOVER_FN_ARGS) + if (!_lv_raid_change_image_count(lv, new_image_count, allocate_pvs, NULL, 0, 1)) + return 0; + +- if (!segtype_is_raid4(new_segtype)) { +- /* Can't convert striped/raid0* to e.g. raid10_offset */ ++ if (segtype_is_raid4(new_segtype) && ++ (!_shift_parity_dev(seg) || ++ !_rename_area_lvs(lv, "_"))) { + log_error("Can't convert %s to %s", display_lvname(lv), new_segtype->name); + return 0; + } +@@ -2987,6 +3218,14 @@ static int _striped_or_raid0_to_raid45610_wrapper(TAKEOVER_FN_ARGS) + if (!_lv_update_reload_fns_reset_eliminate_lvs(lv, NULL)) + return_0; + ++ if (segtype_is_raid4(new_segtype)) { ++ /* We had to rename SubLVs because of collision free sgifting, rename back... */ ++ if (!_rename_area_lvs(lv, NULL)) ++ return 0; ++ if (!lv_update_and_reload(lv)) ++ return_0; ++ } ++ + return 1; + } + +diff --git a/test/shell/lvconvert-raid-takeover.sh b/test/shell/lvconvert-raid-takeover.sh +index 19a65d3..0140e22 100644 +--- a/test/shell/lvconvert-raid-takeover.sh ++++ b/test/shell/lvconvert-raid-takeover.sh +@@ -78,22 +78,58 @@ aux wait_for_sync $vg $lv1 + # Clean up + lvremove --yes $vg/$lv1 + +-# Create 3-way raid0 +-lvcreate -y -aey --type raid0 -i 3 -L 64M -n $lv1 $vg +-check lv_field $vg/$lv1 segtype "raid0" ++# Create 3-way striped ++lvcreate -y -aey --type striped -i 3 -L 64M -n $lv1 $vg ++check lv_field $vg/$lv1 segtype "striped" + check lv_field $vg/$lv1 stripes 3 + echo y | mkfs -t ext4 /dev/mapper/$vg-$lv1 + fsck -fn /dev/mapper/$vg-$lv1 + +-# Convert raid0 -> raid4 ++# Create 3-way raid0 ++lvcreate -y -aey --type raid0 -i 3 -L 64M -n $lv2 $vg ++check lv_field $vg/$lv2 segtype "raid0" ++check lv_field $vg/$lv2 stripes 3 ++echo y | mkfs -t ext4 /dev/mapper/$vg-$lv2 ++fsck -fn /dev/mapper/$vg-$lv2 ++ ++# Create 3-way raid0_meta ++lvcreate -y -aey --type raid0_meta -i 3 -L 64M -n $lv3 $vg ++check lv_field $vg/$lv3 segtype "raid0_meta" ++check lv_field $vg/$lv3 stripes 3 ++echo y | mkfs -t ext4 /dev/mapper/$vg-$lv3 ++fsck -fn /dev/mapper/$vg-$lv3 ++ ++# Create 3-way raid4 ++lvcreate -y -aey --type raid4 -i 3 -L 64M -n $lv4 $vg ++check lv_field $vg/$lv4 segtype "raid4" ++check lv_field $vg/$lv4 stripes 4 ++echo y | mkfs -t ext4 /dev/mapper/$vg-$lv4 ++fsck -fn /dev/mapper/$vg-$lv4 ++aux wait_for_sync $vg $lv4 ++fsck -fn /dev/mapper/$vg-$lv4 ++ ++# Convert raid4 -> striped (correct raid4 mapping test!) ++lvconvert -y --ty striped $vg/$lv4 ++check lv_field $vg/$lv4 segtype "striped" ++check lv_field $vg/$lv4 stripes 3 ++fsck -fn /dev/mapper/$vg-$lv4 ++ ++# Convert striped -> raid4 + lvconvert -y --ty raid4 $vg/$lv1 +-lvchange --refresh $vg/$lv1 + check lv_field $vg/$lv1 segtype "raid4" + check lv_field $vg/$lv1 stripes 4 + fsck -fn /dev/mapper/$vg-$lv1 + aux wait_for_sync $vg $lv1 + fsck -fn /dev/mapper/$vg-$lv1 + ++# Convert raid0 -> raid4 ++lvconvert -y --ty raid4 $vg/$lv2 ++check lv_field $vg/$lv2 segtype "raid4" ++check lv_field $vg/$lv2 stripes 4 ++fsck -fn /dev/mapper/$vg-$lv2 ++aux wait_for_sync $vg $lv2 ++fsck -fn /dev/mapper/$vg-$lv2 ++ + # Convert raid4 -> raid0_meta + lvconvert -y --ty raid0_meta $vg/$lv1 + check lv_field $vg/$lv1 segtype "raid0_meta" +@@ -116,11 +152,16 @@ fsck -fn /dev/mapper/$vg-$lv1 + + # Convert raid0 -> raid4 + lvconvert -y --ty raid4 $vg/$lv1 +-lvchange --refresh $vg/$lv1 + check lv_field $vg/$lv1 segtype "raid4" + check lv_field $vg/$lv1 stripes 4 + fsck -fn /dev/mapper/$vg-$lv1 + aux wait_for_sync $vg $lv1 + fsck -fn /dev/mapper/$vg-$lv1 + ++# Convert raid4 -> striped ++lvconvert -y --ty striped $vg/$lv1 ++check lv_field $vg/$lv1 segtype "striped" ++check lv_field $vg/$lv1 stripes 3 ++fsck -fn /dev/mapper/$vg-$lv1 ++ + vgremove -ff $vg +diff --git a/tools/lvconvert.c b/tools/lvconvert.c +index 0d2a4d1..541df72 100644 +--- a/tools/lvconvert.c ++++ b/tools/lvconvert.c +@@ -1931,7 +1931,7 @@ 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 && !*lp->type_str) { + log_error("Conversion operation not yet supported."); + return 0; + } +@@ -2017,28 +2017,18 @@ static int _lvconvert_raid(struct logical_volume *lv, struct lvconvert_params *l + return 1; + } + +- + try_new_takeover_or_reshape: +- + /* FIXME This needs changing globally. */ + if (!arg_is_set(cmd, stripes_long_ARG)) + lp->stripes = 0; + +- /* Only let raid4 through for now. */ +- if (lp->type_str && lp->type_str[0] && lp->segtype != seg->segtype && +- ((seg_is_raid4(seg) && seg_is_striped(lp) && lp->stripes > 1) || +- (seg_is_striped(seg) && seg->area_count > 1 && seg_is_raid4(lp)))) { +- if (!lv_raid_convert(lv, lp->segtype, lp->yes, lp->force, lp->stripes, lp->stripe_size_supplied, lp->stripe_size, +- lp->region_size, lp->pvh)) +- return_0; +- +- log_print_unless_silent("Logical volume %s successfully converted.", +- display_lvname(lv)); +- return 1; +- } ++ if (!lv_raid_convert(lv, lp->segtype, lp->yes, lp->force, lp->stripes, lp->stripe_size_supplied, lp->stripe_size, ++ lp->region_size, lp->pvh)) ++ return_0; + +- log_error("Conversion operation not yet supported."); +- return 0; ++ log_print_unless_silent("Logical volume %s successfully converted.", ++ display_lvname(lv)); ++ return 1; + } + + static int _lvconvert_splitsnapshot(struct cmd_context *cmd, struct logical_volume *cow, diff --git a/SOURCES/lvm2-2_02_167-prevent-raid4-creation-and-conversion-on-non-supporting-kernels.patch b/SOURCES/lvm2-2_02_167-prevent-raid4-creation-and-conversion-on-non-supporting-kernels.patch new file mode 100644 index 0000000..93eb82e --- /dev/null +++ b/SOURCES/lvm2-2_02_167-prevent-raid4-creation-and-conversion-on-non-supporting-kernels.patch @@ -0,0 +1,303 @@ + WHATS_NEW | 1 + + lib/activate/activate.c | 25 +++++++++++++++++++++++++ + lib/activate/activate.h | 3 ++- + lib/metadata/lv.c | 16 +++++++++++++++- + lib/metadata/segtype.h | 3 ++- + lib/raid/raid.c | 10 ++++++++-- + test/shell/lvconvert-raid-takeover.sh | 13 +++++++++++++ + tools/lvconvert.c | 26 ++++++++++++++++++++++++++ + tools/lvcreate.c | 6 ++++++ + 9 files changed, 98 insertions(+), 5 deletions(-) + +diff --git a/WHATS_NEW b/WHATS_NEW +index 6a0c311..519bbc9 100644 +--- a/WHATS_NEW ++++ b/WHATS_NEW +@@ -1,5 +1,6 @@ + Version 2.02.167 - + ====================================== ++ Prevent raid4 creation/conversion on non-supporting kernels + Add direct striped -> raid4 conversion + Fix raid4 parity image pair position on conversions from striped/raid0* + Disable lvconvert of thin pool to raid while active. +diff --git a/lib/activate/activate.c b/lib/activate/activate.c +index 5550955..571f2b2 100644 +--- a/lib/activate/activate.c ++++ b/lib/activate/activate.c +@@ -370,6 +370,11 @@ void activation_exit(void) + { + } + ++int raid4_is_supported(struct cmd_context *cmd, const struct segment_type *segtype) ++{ ++ return 1; ++} ++ + int lv_is_active(const struct logical_volume *lv) + { + return 0; +@@ -1489,6 +1494,26 @@ out: + return r || l; + } + ++/* ++ * Check if "raid4" @segtype is supported by kernel. ++ * ++ * if segment type is not raid4, return 1. ++ */ ++int raid4_is_supported(struct cmd_context *cmd, const struct segment_type *segtype) ++{ ++ unsigned attrs; ++ ++ if (segtype_is_raid4(segtype) && ++ (!segtype->ops->target_present || ++ !segtype->ops->target_present(cmd, NULL, &attrs) || ++ !(attrs & RAID_FEATURE_RAID4))) { ++ log_error("RAID module does not support RAID4."); ++ return 0; ++ } ++ ++ return 1; ++} ++ + int lv_is_active(const struct logical_volume *lv) + { + return _lv_is_active(lv, NULL, NULL, NULL); +diff --git a/lib/activate/activate.h b/lib/activate/activate.h +index 1e8d7a8..3922d78 100644 +--- a/lib/activate/activate.h ++++ b/lib/activate/activate.h +@@ -1,6 +1,6 @@ + /* + * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. +- * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2004-2016 Red Hat, Inc. All rights reserved. + * + * This file is part of LVM2. + * +@@ -99,6 +99,7 @@ int target_present(struct cmd_context *cmd, const char *target_name, + int use_modprobe); + int target_version(const char *target_name, uint32_t *maj, + uint32_t *min, uint32_t *patchlevel); ++int raid4_is_supported(struct cmd_context *cmd, const struct segment_type *segtype); + int lvm_dm_prefix_check(int major, int minor, const char *prefix); + int list_segment_modules(struct dm_pool *mem, const struct lv_segment *seg, + struct dm_list *modules); +diff --git a/lib/metadata/lv.c b/lib/metadata/lv.c +index 53a1044..0f1b6e7 100644 +--- a/lib/metadata/lv.c ++++ b/lib/metadata/lv.c +@@ -1,6 +1,6 @@ + /* + * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. +- * Copyright (C) 2004-2013 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2004-2016 Red Hat, Inc. All rights reserved. + * + * This file is part of LVM2. + * +@@ -1425,6 +1425,7 @@ int lv_active_change(struct cmd_context *cmd, struct logical_volume *lv, + enum activation_change activate, int needs_exclusive) + { + const char *ay_with_mode = NULL; ++ struct lv_segment *seg = first_seg(lv); + + if (activate == CHANGE_ASY) + ay_with_mode = "sh"; +@@ -1461,6 +1462,9 @@ deactivate: + break; + case CHANGE_ALY: + case CHANGE_AAY: ++ if (!raid4_is_supported(cmd, seg->segtype)) ++ goto no_raid4; ++ + if (needs_exclusive || _lv_is_exclusive(lv)) { + log_verbose("Activating logical volume %s exclusively locally.", + display_lvname(lv)); +@@ -1475,6 +1479,9 @@ deactivate: + break; + case CHANGE_AEY: + exclusive: ++ if (!raid4_is_supported(cmd, seg->segtype)) ++ goto no_raid4; ++ + log_verbose("Activating logical volume %s exclusively.", + display_lvname(lv)); + if (!activate_lv_excl(cmd, lv)) +@@ -1483,6 +1490,9 @@ exclusive: + case CHANGE_ASY: + case CHANGE_AY: + default: ++ if (!raid4_is_supported(cmd, seg->segtype)) ++ goto no_raid4; ++ + if (needs_exclusive || _lv_is_exclusive(lv)) + goto exclusive; + log_verbose("Activating logical volume %s.", display_lvname(lv)); +@@ -1495,6 +1505,10 @@ exclusive: + log_error("Failed to unlock logical volume %s.", display_lvname(lv)); + + return 1; ++ ++no_raid4: ++ log_error("Failed to activate %s LV %s", lvseg_name(seg), display_lvname(lv)); ++ return 0; + } + + char *lv_active_dup(struct dm_pool *mem, const struct logical_volume *lv) +diff --git a/lib/metadata/segtype.h b/lib/metadata/segtype.h +index 9ca740d..292b8b6 100644 +--- a/lib/metadata/segtype.h ++++ b/lib/metadata/segtype.h +@@ -1,6 +1,6 @@ + /* + * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. +- * Copyright (C) 2004-2015 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2004-2016 Red Hat, Inc. All rights reserved. + * + * This file is part of LVM2. + * +@@ -268,6 +268,7 @@ struct segment_type *init_unknown_segtype(struct cmd_context *cmd, + #define RAID_FEATURE_RAID10 (1U << 0) /* version 1.3 */ + #define RAID_FEATURE_RAID0 (1U << 1) /* version 1.7 */ + #define RAID_FEATURE_RESHAPING (1U << 2) /* version 1.8 */ ++#define RAID_FEATURE_RAID4 (1U << 3) /* ! version 1.8 or 1.9.0 */ + + #ifdef RAID_INTERNAL + int init_raid_segtypes(struct cmd_context *cmd, struct segtype_library *seglib); +diff --git a/lib/raid/raid.c b/lib/raid/raid.c +index 3bc3c75..92a96a3 100644 +--- a/lib/raid/raid.c ++++ b/lib/raid/raid.c +@@ -1,5 +1,5 @@ + /* +- * Copyright (C) 2011-2013 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2011-2016 Red Hat, Inc. All rights reserved. + * + * This file is part of LVM2. + * +@@ -366,7 +366,7 @@ static int _raid_target_present(struct cmd_context *cmd, + + static int _raid_checked = 0; + static int _raid_present = 0; +- static int _raid_attrs = 0; ++ static unsigned _raid_attrs = 0; + uint32_t maj, min, patchlevel; + unsigned i; + +@@ -389,6 +389,12 @@ static int _raid_target_present(struct cmd_context *cmd, + else + log_very_verbose("Target raid does not support %s.", + _features[i].feature); ++ ++ if (!(maj == 1 && (min == 8 || (min == 9 && patchlevel == 0)))) ++ _raid_attrs |= RAID_FEATURE_RAID4; ++ else ++ log_very_verbose("Target raid does not support %s.", ++ SEG_TYPE_NAME_RAID4); + } + + if (attributes) +diff --git a/test/shell/lvconvert-raid-takeover.sh b/test/shell/lvconvert-raid-takeover.sh +index 0140e22..332786d 100644 +--- a/test/shell/lvconvert-raid-takeover.sh ++++ b/test/shell/lvconvert-raid-takeover.sh +@@ -16,6 +16,8 @@ SKIP_WITH_LVMPOLLD=1 + + aux have_raid 1 9 0 || skip + ++[ `aux have_raid 1.9.1` ] && correct_raid4_layout=1 ++ + aux prepare_vg 9 288 + + # Delay 1st leg so that rebuilding status characters +@@ -99,6 +101,9 @@ check lv_field $vg/$lv3 stripes 3 + echo y | mkfs -t ext4 /dev/mapper/$vg-$lv3 + fsck -fn /dev/mapper/$vg-$lv3 + ++if [ $correct_raid4_layout -eq 1 ] ++then ++ + # Create 3-way raid4 + lvcreate -y -aey --type raid4 -i 3 -L 64M -n $lv4 $vg + check lv_field $vg/$lv4 segtype "raid4" +@@ -164,4 +169,12 @@ check lv_field $vg/$lv1 segtype "striped" + check lv_field $vg/$lv1 stripes 3 + fsck -fn /dev/mapper/$vg-$lv1 + ++else ++ ++not lvcreate -y -aey --type raid4 -i 3 -L 64M -n $lv4 $vg ++not lvconvert -y --ty raid4 $vg/$lv1 ++not lvconvert -y --ty raid4 $vg/$lv2 ++ ++fi ++ + vgremove -ff $vg +diff --git a/tools/lvconvert.c b/tools/lvconvert.c +index 541df72..7a4215a 100644 +--- a/tools/lvconvert.c ++++ b/tools/lvconvert.c +@@ -1821,6 +1821,25 @@ static void _lvconvert_raid_repair_ask(struct cmd_context *cmd, + } + } + ++/* Check for dm-raid target supporting raid4 conversion properly. */ ++static int _raid4_conversion_supported(struct logical_volume *lv, struct lvconvert_params *lp) ++{ ++ int ret = 1; ++ struct lv_segment *seg = first_seg(lv); ++ ++ if (seg_is_raid4(seg)) ++ ret = raid4_is_supported(lv->vg->cmd, seg->segtype); ++ else if (segtype_is_raid4(lp->segtype)) ++ ret = raid4_is_supported(lv->vg->cmd, lp->segtype); ++ ++ if (ret) ++ return 1; ++ ++ log_error("Cannot convert %s LV %s to %s.", ++ lvseg_name(seg), display_lvname(lv), lp->segtype->name); ++ return 0; ++} ++ + static int _lvconvert_raid(struct logical_volume *lv, struct lvconvert_params *lp) + { + int replace = 0, image_count = 0; +@@ -1945,6 +1964,9 @@ static int _lvconvert_raid(struct logical_volume *lv, struct lvconvert_params *l + return 0; + } + ++ if (!_raid4_conversion_supported(lv, lp)) ++ return 0; ++ + if (!arg_is_set(cmd, stripes_long_ARG)) + lp->stripes = 0; + +@@ -2018,6 +2040,10 @@ static int _lvconvert_raid(struct logical_volume *lv, struct lvconvert_params *l + } + + try_new_takeover_or_reshape: ++ ++ if (!_raid4_conversion_supported(lv, lp)) ++ return 0; ++ + /* FIXME This needs changing globally. */ + if (!arg_is_set(cmd, stripes_long_ARG)) + lp->stripes = 0; +diff --git a/tools/lvcreate.c b/tools/lvcreate.c +index 387c8d4..dbc0708 100644 +--- a/tools/lvcreate.c ++++ b/tools/lvcreate.c +@@ -1054,6 +1054,12 @@ static int _lvcreate_params(struct cmd_context *cmd, + return 0; + } + ++ if (segtype_is_raid4(lp->segtype) && ++ !(lp->target_attr & RAID_FEATURE_RAID4)) { ++ log_error("RAID module does not support RAID4."); ++ return 0; ++ } ++ + if (segtype_is_raid10(lp->segtype) && !(lp->target_attr & RAID_FEATURE_RAID10)) { + log_error("RAID module does not support RAID10."); + return 0; diff --git a/SOURCES/lvm2-rhel7.patch b/SOURCES/lvm2-rhel7.patch index 4b0c686..b029dce 100644 --- a/SOURCES/lvm2-rhel7.patch +++ b/SOURCES/lvm2-rhel7.patch @@ -8,11 +8,11 @@ index dd4e60e..39d6c15 100644 +++ b/VERSION @@ -1 +1 @@ -2.02.166(2) (2016-09-26) -+2.02.166(2)-RHEL7 (2016-09-28) ++2.02.166(2)-RHEL7 (2016-11-16) diff --git a/VERSION_DM b/VERSION_DM index d53f47a..005fbd4 100644 --- a/VERSION_DM +++ b/VERSION_DM @@ -1 +1 @@ -1.02.135 (2016-09-26) -+1.02.135-RHEL7 (2016-09-28) ++1.02.135-RHEL7 (2016-11-16) diff --git a/SPECS/lvm2.spec b/SPECS/lvm2.spec index 557beac..4b808ad 100644 --- a/SPECS/lvm2.spec +++ b/SPECS/lvm2.spec @@ -51,7 +51,7 @@ Summary: Userland logical volume management tools Name: lvm2 Epoch: 7 Version: 2.02.166 -Release: 1%{?dist}.1 +Release: 1%{?dist}.2 License: GPLv2 Group: System Environment/Base URL: http://sources.redhat.com/lvm2 @@ -64,6 +64,8 @@ Patch4: lvm2-default-allow-changes-with-duplicate-pvs.patch Patch5: lvm2-revert-fix-for-lvconvert-repair-for-raid-lvs.patch Patch6: lvm2-2_02_167-disable-lvconvert-of-thin-pool-to-raid-while-active.patch Patch7: lvm2-2_02_167-fix-inability-of-lvconvert-repair-for-cache-raid-volumes.patch +Patch8: lvm2-2_02_167-fix-raid4-coversion-from-striped.patch +Patch9: lvm2-2_02_167-prevent-raid4-creation-and-conversion-on-non-supporting-kernels.patch BuildRequires: libselinux-devel >= %{libselinux_version}, libsepol-devel BuildRequires: libblkid-devel >= %{util_linux_version} @@ -117,6 +119,8 @@ or more physical volumes and creating one or more logical volumes %patch5 -p1 -b .lvconvert_repair_raid %patch6 -p1 -b .lvconvert_disable_thin_pool_to_raid %patch7 -p1 -b .lvconvert_cache_raid +%patch8 -p1 -b .raid4_from_striped +%patch9 -p1 -b .raid4_vs_kernel %build %global _default_pid_dir /run @@ -819,6 +823,11 @@ the device-mapper event library. %{_libdir}/pkgconfig/devmapper-event.pc %changelog +* Wed Nov 16 2016 Peter Rajnoha - 7:2.02.166-1.el7_3.2 +- Prevent raid4 creation/conversion on non-supporting kernels +- Add direct striped -> raid4 conversion +- Fix raid4 parity image pair position on conversions from striped/raid0* + * Wed Oct 12 2016 Peter Rajnoha - 7:2.02.166-1.el7_3.1 - Fix lvconvert to allow repair for cache raid LVs. - Fix time when dmeventd is reloaded on package upgrade to start using new code.