From d18f141e6cab02695b9336edf9067b5fdaf92e41 Mon Sep 17 00:00:00 2001 From: zhuhong_bo Date: Thu, 11 Dec 2025 17:18:14 +0800 Subject: [PATCH] mirror: enhance error path for pvmove finish --- ...enhance-error-path-for-pvmove-finish.patch | 183 ++++++++++++++++++ lvm2.spec | 9 +- 2 files changed, 191 insertions(+), 1 deletion(-) create mode 100644 lvm2-2_03_32-mirror-enhance-error-path-for-pvmove-finish.patch diff --git a/lvm2-2_03_32-mirror-enhance-error-path-for-pvmove-finish.patch b/lvm2-2_03_32-mirror-enhance-error-path-for-pvmove-finish.patch new file mode 100644 index 0000000..e308d73 --- /dev/null +++ b/lvm2-2_03_32-mirror-enhance-error-path-for-pvmove-finish.patch @@ -0,0 +1,183 @@ +From 6fb5fdaca0938b50f7b19a6cab19df9af3d2b4c1 Mon Sep 17 00:00:00 2001 +From: zhuhongbo +Date: Tue, 9 Dec 2025 13:13:05 +0800 +Subject: [PATCH] mirror: enhance error path for pvmove finish + +--- + lib/metadata/mirror.c | 93 ++++++++++++++++++++++++++++++++++++++++--- + tools/pvmove_poll.c | 13 ++++++ + 2 files changed, 101 insertions(+), 5 deletions(-) + +diff --git a/lib/metadata/mirror.c b/lib/metadata/mirror.c +index 068ebd2c5..8ba0b9d4b 100644 +--- a/lib/metadata/mirror.c ++++ b/lib/metadata/mirror.c +@@ -442,6 +442,59 @@ static int _activate_lv_like_model(struct logical_volume *model, + return 1; + } + ++/* ++ * Inherit tags @from_lv to @to_lv, tags maybe needed for activation ++ */ ++static int _inherit_lv_tags(const struct logical_volume *from_lv, struct logical_volume *to_lv) ++{ ++ struct dm_str_list *sl; ++ ++ if (to_lv && !str_list_match_list(&from_lv->tags, &to_lv->tags, NULL)) ++ dm_list_iterate_items(sl, &from_lv->tags) ++ if (!str_list_add(from_lv->vg->cmd->mem, &to_lv->tags, sl->str)) { ++ log_error("Aborting. Unable to inherit tag."); ++ return 0; ++ } ++ ++ return 1; ++} ++ ++/* ++ * Deactivates and removes an 'orphan' temporary @lv, ++ * which is expected to already have an 'error' segment. ++ * Sets @updated_mda (!NULL) to 1 when LV is removed. ++ * Sets @deactivation_failed (!NULL) to 1 when deactivation fails. ++ * ++ * Note: An external tool might still have the volume open, preventing ++ * immediate deactivation. If deactivation fails (even after retrying), ++ * it is safer to proceed with the command and leave the LV visible. ++ * This allows the user to manually remove it when it is no longer in use. ++ * ++ * Any errors will be detected later in the process, as there will be ++ * more visible LVs than expected. ++ */ ++static int _deactivate_and_remove_lv(struct logical_volume *lv, ++ int *updated_mda, ++ int *deactivation_failed) ++{ ++ if (lv) { ++ /* FIXME: convert to use lv_active_change() */ ++ if (!deactivate_lv(lv->vg->cmd, lv)) { ++ /* Note: still returns success here and fails later */ ++ log_warn("WARNING: Can't deactivate temporary volume %s.", ++ display_lvname(lv)); ++ if (deactivation_failed) ++ *deactivation_failed = 1; ++ } else if (!lv_remove(lv)) { ++ /* Can't continue with internal metadata problems */ ++ return_0; ++ } else if (updated_mda) ++ *updated_mda = 1; ++ } ++ ++ return 1; ++} ++ + /* + * Delete independent/orphan LV, it must acquire lock. + */ +@@ -848,7 +901,6 @@ static int _remove_mirror_images(struct logical_volume *lv, + struct lv_list *lvl; + struct dm_list tmp_orphan_lvs; + uint32_t orig_removed = num_removed; +- int reactivate; + + if (removed) + *removed = 0; +@@ -1012,6 +1064,19 @@ static int _remove_mirror_images(struct logical_volume *lv, + return_0; + } + ++ if (!collapse) { ++ dm_list_iterate_items(lvl, &tmp_orphan_lvs) { ++ if (!_inherit_lv_tags(lv, lvl->lv)) ++ return_0; ++ if (!replace_lv_with_error_segment(lvl->lv)) ++ return_0; ++ } ++ } ++ ++ if (!_inherit_lv_tags(lv, temp_layer_lv) || ++ !_inherit_lv_tags(lv, detached_log_lv)) ++ return_0; ++ + /* + * To successfully remove these unwanted LVs we need to + * remove the LVs from the mirror set, commit that metadata +@@ -1021,17 +1086,35 @@ static int _remove_mirror_images(struct logical_volume *lv, + return_0; + + /* Save or delete the 'orphan' LVs */ +- reactivate = lv_is_active(lv_lock_holder(lv)); ++ if (lv_is_active(lv_lock_holder(lv))) { ++ if (!collapse) { ++ dm_list_iterate_items(lvl, &tmp_orphan_lvs) ++ if (!_activate_lv_like_model(lv, lvl->lv)) ++ return_0; ++ } ++ ++ if (temp_layer_lv && ++ !_activate_lv_like_model(lv, temp_layer_lv)) ++ return_0; ++ ++ if (detached_log_lv && ++ !_activate_lv_like_model(lv, detached_log_lv)) ++ return_0; ++ ++ if (!sync_local_dev_names(lv->vg->cmd)) ++ stack; ++ } ++ + if (!collapse) { + dm_list_iterate_items(lvl, &tmp_orphan_lvs) +- if (!_delete_lv(lv, lvl->lv, reactivate)) ++ if (!_deactivate_and_remove_lv(lvl->lv, NULL, NULL)) + return_0; + } + +- if (temp_layer_lv && !_delete_lv(lv, temp_layer_lv, reactivate)) ++ if (!_deactivate_and_remove_lv(temp_layer_lv, NULL, NULL)) + return_0; + +- if (detached_log_lv && !_delete_lv(lv, detached_log_lv, reactivate)) ++ if (!_deactivate_and_remove_lv(detached_log_lv, NULL, NULL)) + return_0; + + /* Mirror with only 1 area is 'in sync'. */ +diff --git a/tools/pvmove_poll.c b/tools/pvmove_poll.c +index d379596f2..05c5c2c01 100644 +--- a/tools/pvmove_poll.c ++++ b/tools/pvmove_poll.c +@@ -87,6 +87,8 @@ int pvmove_update_metadata(struct cmd_context *cmd, struct volume_group *vg, + int pvmove_finish(struct cmd_context *cmd, struct volume_group *vg, + struct logical_volume *lv_mirr, struct dm_list *lvs_changed) + { ++ uint32_t visible = vg_visible_lvs(lv_mirr->vg); ++ + if (!dm_list_empty(lvs_changed) && + (!_detach_pvmove_mirror(cmd, lv_mirr) || + !replace_lv_with_error_segment(lv_mirr))) { +@@ -94,6 +96,8 @@ int pvmove_finish(struct cmd_context *cmd, struct volume_group *vg, + return 0; + } + ++ lv_set_visible(lv_mirr); ++ + if (!lv_update_and_reload(lv_mirr)) + return_0; + +@@ -120,6 +124,15 @@ int pvmove_finish(struct cmd_context *cmd, struct volume_group *vg, + return 0; + } + ++ /* Allows the pvmove operation to complete even if 'orphaned' temporary volumes ++ * cannot be deactivated due to being held open by another process. ++ * The user can manually remove these volumes later when they are no longer in use. */ ++ if (visible < vg_visible_lvs(lv_mirr->vg)) { ++ log_error("ABORTING: Failed to remove temporary logical volume(s)."); ++ log_print_unless_silent("Please remove orphan temporary logical volume(s) when possible."); ++ return 0; ++ } ++ + /* FIXME backup positioning */ + backup(vg); + +-- +2.48.1 + diff --git a/lvm2.spec b/lvm2.spec index 8f9a8e9..718c4c4 100644 --- a/lvm2.spec +++ b/lvm2.spec @@ -33,7 +33,7 @@ %global boom_dir boom-%{boom_version} #%%global scratch .bz1628529_4 -%global scratch .5 +%global scratch .6 %if 0%{?rhel} %ifnarch i686 x86_64 ppc64le s390x @@ -103,9 +103,11 @@ Patch22: lvm2-2_02_188-fsadm-avoid-access-to-unbound-variable.patch # BZ 1926569: Patch23: lvm2-2_02_188-vgextend-check-missing-device-during-block-size-chec.patch # BZ 1777364: +Patch24: lvm2-2_03_32-mirror-enhance-error-path-for-pvmove-finish.patch Patch50: boom-etc-Remove-executable-permission-from-etc-default-bo.patch Patch51: boom-man-Fix-line-starting-with.patch + BuildRequires: libselinux-devel >= %{libselinux_version}, libsepol-devel BuildRequires: libblkid-devel >= %{util_linux_version} BuildRequires: ncurses-devel @@ -183,6 +185,7 @@ or more physical volumes and creating one or more logical volumes %patch21 -p1 -b .fsadm_fix_unbound_variable_usage %patch22 -p1 -b .fsadm_avoid_access_to_unbound_variable %patch23 -p1 -b .vgextend_check_missing_device_during_block_size_check +%patch24 -p1 -b .mirror_enhance_error_path_for_pvmove_finish %build %global _default_pid_dir /run @@ -1003,6 +1006,10 @@ This package provides the python2 version of boom. %endif %changelog +* Thu Dec 11 2025 zhuhongbo - 7:2.02.187-6.an7.6 +- Fix bad metadata on pvmove exit with temp device kept open by a third party +- mirror: enhance error path for pvmove finish + * Thu Mar 11 2021 Marian Csontos - 7:2.02.187-6.el7_9.5 - Fix fsadm failure due to accessing unbound variable. - Fix segfault in vgextend when a PV is missing in the processed VG. -- Gitee