From b5e43fdc0847364095ac8ebdf5894e9def31ba8c Mon Sep 17 00:00:00 2001 From: AlmaLinux RelEng Bot Date: Mon, 30 Mar 2026 10:44:19 -0400 Subject: [PATCH] import CS lvm2-2.03.33-4.el9 --- .gitignore | 2 +- .lvm2.metadata | 2 +- SOURCES/0001-RHEL9.patch | 19 +- ...dm.rules-bump-DM_UDEV_RULES_VSN-to-3.patch | 8 +- ...ules-don-t-export-and-save-DM_NOSCAN.patch | 8 +- ...ules-don-t-export-and-save-DM_SUSPEN.patch | 8 +- ....rules-don-t-restore-DM_UDEV_DISABLE.patch | 8 +- ...es-don-t-restore-DM_UDEV_DISABLE_OTH.patch | 8 +- SOURCES/0007-WHATS_NEW_DM-update.patch | 28 +- ...vmlockd-fix-hosts-check-for-vgremove.patch | 143 ---- ...mlockd-fix-missing-free-in-vg_status.patch | 50 ++ ...air-option-to-reinitialize-sanlock-l.patch | 686 ++++++++++++++++++ ...ckd-fix-sanlock_release-for-vgremove.patch | 38 - ...-or-clear-transiently-failed-devices.patch | 460 ------------ ...utoactivation-on-top-of-loop-dev-PVs.patch | 54 ++ ...vresize-corruption-in-LV-crypt-FS-st.patch | 81 +++ ...lvconvert-allow-clearing-superblocks.patch | 64 -- ...-log_error-on-device-ids-write-error.patch | 32 + ...-test-check-raid-superblock-clearing.patch | 107 --- ...n-error-if-writing-device-ids-fail-f.patch | 48 ++ SOURCES/0013-man-update-raid-man.patch | 50 -- SOURCES/0014-WHATS_NEW-update.patch | 33 +- ...rn-instead-of-log_error-in-device_id.patch | 103 +++ ...rror-when-writing-devices-file-fails.patch | 97 +++ ...-was-mistakenly-ignored-when-nolocki.patch | 56 ++ ...lock-match-lm_lock_sanlock-prototype.patch | 26 + ...-fix-struct-pointer-in-release_renam.patch | 28 + ...ckd-free-structs-in-adopt-error-path.patch | 33 + ...-check-lock_lv_offset_from_args-resu.patch | 27 + ...free-ls-struct-after-ls-thread-exits.patch | 57 ++ SOURCES/0023-man-lvmlockd-updates.patch | 582 +++++++++++++++ ...vmlockd-allow-1-more-extra-character.patch | 44 ++ ...-fix-type-mismatch-in-bit-operations.patch | 113 +++ ...event-potential-negative-array-index.patch | 41 ++ ...integer-underflow-in-_count-handling.patch | 65 ++ ...-fix-va_end-resource-leak-in-szscanf.patch | 39 + ...29-cov-add-explicit-check-for-0-size.patch | 44 ++ ...licitly-zero-allocated-mem-for-array.patch | 47 ++ ...ck-for-potential-empty-registry-list.patch | 34 + ...v-check-for-potential-empty-row-list.patch | 54 ++ ...r-C90-don-t-mix-declaration-and-code.patch | 61 ++ ...struct-copy-to-avoid-aliasing-issues.patch | 35 + ...x-file-descriptor-leak-in-error-path.patch | 33 + ...-lines-fix-typo-in-configurable-name.patch | 30 + ...fy-LVM_DID_EXEC-environment-variable.patch | 30 + ...sure-pointer-is-properly-initialized.patch | 39 + .../0039-dmeventd-check-device-exists.patch | 40 + ...-dmeventd-add-device-existence-check.patch | 53 ++ ...atus-returns-success-for-non-monitor.patch | 37 + ...k-for-not-splitting-an-LV-between-tw.patch | 58 ++ ...k-for-not-splitting-an-LV-between-tw.patch | 88 +++ ...t-create-system.devices-when-deletin.patch | 51 ++ ...nlock-devices-file-at-the-end-of-cmd.patch | 51 ++ ...nlock-devices-file-at-the-end-of-cmd.patch | 28 + SOURCES/0047-make-generate.patch | 162 +++++ ...LV-with-partial-snapshot-is-an-error.patch | 48 ++ ...warning-during-classic-snapshot-crea.patch | 34 + ...t-for-snapshot-on-raid-creation-acti.patch | 67 ++ SOURCES/0051-WHATS_NEW-update.patch | 36 + ...creating-imeta-with-more-than-one-se.patch | 240 ++++++ .../0053-lvresize-fix-xfs-size-checks.patch | 350 +++++++++ ...-configure-check-for-xfs-header-file.patch | 37 + SOURCES/0055-log-add-string.h.patch | 27 + ...ystem-refactor-code-working-with-xfs.patch | 208 ++++++ SOURCES/0057-lib-rename-uuid.c-to-id.c.patch | 210 ++++++ SOURCES/0058-autoreconf-reconfigure.patch | 113 +++ SPECS/lvm2.spec | 81 ++- 67 files changed, 4743 insertions(+), 931 deletions(-) delete mode 100644 SOURCES/0008-lvmlockd-fix-hosts-check-for-vgremove.patch create mode 100644 SOURCES/0008-lvmlockd-fix-missing-free-in-vg_status.patch create mode 100644 SOURCES/0009-lvmlockd-add-repair-option-to-reinitialize-sanlock-l.patch delete mode 100644 SOURCES/0009-lvmlockd-fix-sanlock_release-for-vgremove.patch delete mode 100644 SOURCES/0010-raid-count-or-clear-transiently-failed-devices.patch create mode 100644 SOURCES/0010-udev-fix-autoactivation-on-top-of-loop-dev-PVs.patch create mode 100644 SOURCES/0011-lv_manip.c-fix-lvresize-corruption-in-LV-crypt-FS-st.patch delete mode 100644 SOURCES/0011-lvconvert-allow-clearing-superblocks.patch create mode 100644 SOURCES/0012-device_id-always-log_error-on-device-ids-write-error.patch delete mode 100644 SOURCES/0012-test-check-raid-superblock-clearing.patch create mode 100644 SOURCES/0013-lvmdevices-return-error-if-writing-device-ids-fail-f.patch delete mode 100644 SOURCES/0013-man-update-raid-man.patch create mode 100644 SOURCES/0015-device_id-log_warn-instead-of-log_error-in-device_id.patch create mode 100644 SOURCES/0016-lvmdevices-log_error-when-writing-devices-file-fails.patch create mode 100644 SOURCES/0017-lvmlockd-lockopt-was-mistakenly-ignored-when-nolocki.patch create mode 100644 SOURCES/0018-sanlock-match-lm_lock_sanlock-prototype.patch create mode 100644 SOURCES/0019-lvmlockd-sanlock-fix-struct-pointer-in-release_renam.patch create mode 100644 SOURCES/0020-lvmlockd-free-structs-in-adopt-error-path.patch create mode 100644 SOURCES/0021-lvmlockd-sanlock-check-lock_lv_offset_from_args-resu.patch create mode 100644 SOURCES/0022-lvmlockd-always-free-ls-struct-after-ls-thread-exits.patch create mode 100644 SOURCES/0023-man-lvmlockd-updates.patch create mode 100644 SOURCES/0024-lvmlockd-allow-1-more-extra-character.patch create mode 100644 SOURCES/0025-libdm-stats-fix-type-mismatch-in-bit-operations.patch create mode 100644 SOURCES/0026-cov-prevent-potential-negative-array-index.patch create mode 100644 SOURCES/0027-cov-fix-integer-underflow-in-_count-handling.patch create mode 100644 SOURCES/0028-cov-fix-va_end-resource-leak-in-szscanf.patch create mode 100644 SOURCES/0029-cov-add-explicit-check-for-0-size.patch create mode 100644 SOURCES/0030-cov-explicitly-zero-allocated-mem-for-array.patch create mode 100644 SOURCES/0031-cov-check-for-potential-empty-registry-list.patch create mode 100644 SOURCES/0032-cov-check-for-potential-empty-row-list.patch create mode 100644 SOURCES/0033-gcc-for-C90-don-t-mix-declaration-and-code.patch create mode 100644 SOURCES/0034-sanlock-fix-struct-copy-to-avoid-aliasing-issues.patch create mode 100644 SOURCES/0035-sanlock-fix-file-descriptor-leak-in-error-path.patch create mode 100644 SOURCES/0036-command-lines-fix-typo-in-configurable-name.patch create mode 100644 SOURCES/0037-tools-simplify-LVM_DID_EXEC-environment-variable.patch create mode 100644 SOURCES/0038-gcc-ensure-pointer-is-properly-initialized.patch create mode 100644 SOURCES/0039-dmeventd-check-device-exists.patch create mode 100644 SOURCES/0040-dmeventd-add-device-existence-check.patch create mode 100644 SOURCES/0041-dmeventd-_get_status-returns-success-for-non-monitor.patch create mode 100644 SOURCES/0042-vgsplit-fix-check-for-not-splitting-an-LV-between-tw.patch create mode 100644 SOURCES/0043-vgsplit-fix-check-for-not-splitting-an-LV-between-tw.patch create mode 100644 SOURCES/0044-lvmdevices-do-not-create-system.devices-when-deletin.patch create mode 100644 SOURCES/0045-tools-pvchange-unlock-devices-file-at-the-end-of-cmd.patch create mode 100644 SOURCES/0046-tools-pvchange-unlock-devices-file-at-the-end-of-cmd.patch create mode 100644 SOURCES/0047-make-generate.patch create mode 100644 SOURCES/0048-activating-raid-LV-with-partial-snapshot-is-an-error.patch create mode 100644 SOURCES/0049-lv_manip-show-a-warning-during-classic-snapshot-crea.patch create mode 100644 SOURCES/0050-test-add-new-test-for-snapshot-on-raid-creation-acti.patch create mode 100644 SOURCES/0051-WHATS_NEW-update.patch create mode 100644 SOURCES/0052-integrity-allow-creating-imeta-with-more-than-one-se.patch create mode 100644 SOURCES/0053-lvresize-fix-xfs-size-checks.patch create mode 100644 SOURCES/0054-configure-check-for-xfs-header-file.patch create mode 100644 SOURCES/0055-log-add-string.h.patch create mode 100644 SOURCES/0056-filesystem-refactor-code-working-with-xfs.patch create mode 100644 SOURCES/0057-lib-rename-uuid.c-to-id.c.patch create mode 100644 SOURCES/0058-autoreconf-reconfigure.patch diff --git a/.gitignore b/.gitignore index 026dd67..2d523eb 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -SOURCES/LVM2.2.03.32.tgz +SOURCES/LVM2.2.03.33.tgz diff --git a/.lvm2.metadata b/.lvm2.metadata index cd0e57f..4e760ad 100644 --- a/.lvm2.metadata +++ b/.lvm2.metadata @@ -1 +1 @@ -6b0df2dddc2ee883380969362f5e5d1e89a6960d SOURCES/LVM2.2.03.32.tgz +63bb26807fa2dc9b8df29525bd854335a278eed5 SOURCES/LVM2.2.03.33.tgz diff --git a/SOURCES/0001-RHEL9.patch b/SOURCES/0001-RHEL9.patch index 5f7775c..55b6150 100644 --- a/SOURCES/0001-RHEL9.patch +++ b/SOURCES/0001-RHEL9.patch @@ -1,27 +1,28 @@ -From 4487d3c0b4e9e1bbb966a40876b2e481b90865a8 Mon Sep 17 00:00:00 2001 +From 826517119e31658ac9f91940816281a44b0af4e9 Mon Sep 17 00:00:00 2001 From: Marian Csontos Date: Thu, 3 Oct 2024 16:14:11 +0200 -Subject: [PATCH 1/7] RHEL9 +Subject: [PATCH 01/47] RHEL9 +(cherry picked from commit 4ed40e67197778b28e4b822558614a517242e3e1) --- VERSION | 2 +- VERSION_DM | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/VERSION b/VERSION -index e1934c88c..e4e055d17 100644 +index 2d35b7660..4993d445a 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ --2.03.32(2) (2025-05-05) -+2.03.32(2)-RHEL9 (2025-05-05) +-2.03.33(2) (2025-06-27) ++2.03.33(2)-RHEL9 (2025-09-25) diff --git a/VERSION_DM b/VERSION_DM -index 9016990a1..ea3811ba7 100644 +index 0e8dcd346..c0564e0ea 100644 --- a/VERSION_DM +++ b/VERSION_DM @@ -1 +1 @@ --1.02.206 (2025-05-05) -+1.02.206-RHEL9 (2025-05-05) +-1.02.207 (2025-06-27) ++1.02.207-RHEL9 (2025-09-25) -- -2.49.0 +2.51.0 diff --git a/SOURCES/0002-Revert-10-dm.rules-bump-DM_UDEV_RULES_VSN-to-3.patch b/SOURCES/0002-Revert-10-dm.rules-bump-DM_UDEV_RULES_VSN-to-3.patch index 18a326b..557f11f 100644 --- a/SOURCES/0002-Revert-10-dm.rules-bump-DM_UDEV_RULES_VSN-to-3.patch +++ b/SOURCES/0002-Revert-10-dm.rules-bump-DM_UDEV_RULES_VSN-to-3.patch @@ -1,9 +1,11 @@ -From 408a80fdd46d3854c92dfce1bff3a376aea611d1 Mon Sep 17 00:00:00 2001 +From c7b8367ebd23acbc63d657d3be822069cdb22e29 Mon Sep 17 00:00:00 2001 From: Marian Csontos Date: Thu, 16 May 2024 15:30:02 +0200 -Subject: [PATCH 2/7] Revert "10-dm.rules: bump DM_UDEV_RULES_VSN to 3" +Subject: [PATCH 02/47] Revert "10-dm.rules: bump DM_UDEV_RULES_VSN to 3" This reverts commit 038f9254d9554654197b59c160e3f775af27cdb1. + +(cherry picked from commit 408a80fdd46d3854c92dfce1bff3a376aea611d1) --- udev/10-dm.rules.in | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) @@ -46,5 +48,5 @@ index db4ee771d..ca255c793 100644 ENV{DM_UDEV_DISABLE_DM_RULES_FLAG}!="1", ENV{DM_NAME}=="?*", SYMLINK+="(DM_DIR)/$env{DM_NAME}" -- -2.49.0 +2.51.0 diff --git a/SOURCES/0003-Revert-dm-udev-rules-don-t-export-and-save-DM_NOSCAN.patch b/SOURCES/0003-Revert-dm-udev-rules-don-t-export-and-save-DM_NOSCAN.patch index b359940..54ad9e1 100644 --- a/SOURCES/0003-Revert-dm-udev-rules-don-t-export-and-save-DM_NOSCAN.patch +++ b/SOURCES/0003-Revert-dm-udev-rules-don-t-export-and-save-DM_NOSCAN.patch @@ -1,9 +1,11 @@ -From 6a15577cb02603512afce0f13a591183105c8f73 Mon Sep 17 00:00:00 2001 +From e7afa38ae6a12cb0ac0d4c7b923ec46c254df553 Mon Sep 17 00:00:00 2001 From: Marian Csontos Date: Thu, 16 May 2024 15:30:15 +0200 -Subject: [PATCH 3/7] Revert "dm udev rules: don't export and save DM_NOSCAN" +Subject: [PATCH 03/47] Revert "dm udev rules: don't export and save DM_NOSCAN" This reverts commit a196752969320cfc34a97cc97afa1978fa57da73. + +(cherry picked from commit 6a15577cb02603512afce0f13a591183105c8f73) --- udev/11-dm-lvm.rules.in | 2 +- udev/13-dm-disk.rules.in | 4 ++-- @@ -39,5 +41,5 @@ index 9bfeebe13..a9ad67e9f 100644 (BLKID_RULE) GOTO="dm_link" -- -2.49.0 +2.51.0 diff --git a/SOURCES/0004-Revert-dm-udev-rules-don-t-export-and-save-DM_SUSPEN.patch b/SOURCES/0004-Revert-dm-udev-rules-don-t-export-and-save-DM_SUSPEN.patch index a52af49..f200460 100644 --- a/SOURCES/0004-Revert-dm-udev-rules-don-t-export-and-save-DM_SUSPEN.patch +++ b/SOURCES/0004-Revert-dm-udev-rules-don-t-export-and-save-DM_SUSPEN.patch @@ -1,10 +1,12 @@ -From 2280f85310b82c03b43dfd88e0712c5921a36ffc Mon Sep 17 00:00:00 2001 +From c58cdd59d2028c5eca83cdf5df16948b4277a21f Mon Sep 17 00:00:00 2001 From: Marian Csontos Date: Thu, 16 May 2024 15:30:24 +0200 -Subject: [PATCH 4/7] Revert "dm udev rules: don't export and save +Subject: [PATCH 04/47] Revert "dm udev rules: don't export and save DM_SUSPENDED" This reverts commit 21ca92c4325b6b161fb1e1f10942ad9f8d23c144. + +(cherry picked from commit 2280f85310b82c03b43dfd88e0712c5921a36ffc) --- udev/10-dm.rules.in | 14 ++++++-------- udev/12-dm-permissions.rules | 1 + @@ -84,5 +86,5 @@ index a9ad67e9f..e136ee441 100644 (BLKID_RULE) -- -2.49.0 +2.51.0 diff --git a/SOURCES/0005-Revert-11-dm-lvm.rules-don-t-restore-DM_UDEV_DISABLE.patch b/SOURCES/0005-Revert-11-dm-lvm.rules-don-t-restore-DM_UDEV_DISABLE.patch index 1e56f78..aec38df 100644 --- a/SOURCES/0005-Revert-11-dm-lvm.rules-don-t-restore-DM_UDEV_DISABLE.patch +++ b/SOURCES/0005-Revert-11-dm-lvm.rules-don-t-restore-DM_UDEV_DISABLE.patch @@ -1,10 +1,12 @@ -From 4316c786f25f8b01b831458f8baf1f77faad79ba Mon Sep 17 00:00:00 2001 +From 1ab5db0e811306dafabcd7281ce84ffbe32b2566 Mon Sep 17 00:00:00 2001 From: Marian Csontos Date: Thu, 16 May 2024 15:30:37 +0200 -Subject: [PATCH 5/7] Revert "11-dm-lvm.rules: don't restore +Subject: [PATCH 05/47] Revert "11-dm-lvm.rules: don't restore DM_UDEV_DISABLE_OTHER_RULES_FLAG from db" This reverts commit 2b2f11a74cd5cc05f266fd0c65f0e55eb8bafd9f. + +(cherry picked from commit 4316c786f25f8b01b831458f8baf1f77faad79ba) --- udev/11-dm-lvm.rules.in | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) @@ -34,5 +36,5 @@ index 6dd556aa9..9836f41ca 100644 ENV{DM_UDEV_DISABLE_SUBSYSTEM_RULES_FLAG}=="1", GOTO="lvm_end" -- -2.49.0 +2.51.0 diff --git a/SOURCES/0006-Revert-10-dm-rules-don-t-restore-DM_UDEV_DISABLE_OTH.patch b/SOURCES/0006-Revert-10-dm-rules-don-t-restore-DM_UDEV_DISABLE_OTH.patch index 8f4a6c0..a4710b1 100644 --- a/SOURCES/0006-Revert-10-dm-rules-don-t-restore-DM_UDEV_DISABLE_OTH.patch +++ b/SOURCES/0006-Revert-10-dm-rules-don-t-restore-DM_UDEV_DISABLE_OTH.patch @@ -1,10 +1,12 @@ -From ebd5feaca2779c9379a14ba6f74a47214d03d94b Mon Sep 17 00:00:00 2001 +From 2d8f649144bd95cf2df65f1d4bd99c96a8c5f786 Mon Sep 17 00:00:00 2001 From: Marian Csontos Date: Thu, 16 May 2024 15:30:48 +0200 -Subject: [PATCH 6/7] Revert "10-dm-rules: don't restore +Subject: [PATCH 06/47] Revert "10-dm-rules: don't restore DM_UDEV_DISABLE_OTHER_RULES_FLAG from db" This reverts commit f98d020eadafe7d8db7bec1f5a26915615e5a6a9. + +(cherry picked from commit ebd5feaca2779c9379a14ba6f74a47214d03d94b) --- udev/10-dm.rules.in | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) @@ -45,5 +47,5 @@ index 29fe71527..2c6903da7 100644 # If DISK_RO is set, it's an uevent that changes the ro attribute of the device. -- -2.49.0 +2.51.0 diff --git a/SOURCES/0007-WHATS_NEW_DM-update.patch b/SOURCES/0007-WHATS_NEW_DM-update.patch index 6207b18..740eb10 100644 --- a/SOURCES/0007-WHATS_NEW_DM-update.patch +++ b/SOURCES/0007-WHATS_NEW_DM-update.patch @@ -1,30 +1,28 @@ -From 72f203a02d7f30d5afdaa853a082b2b1d1f56297 Mon Sep 17 00:00:00 2001 +From 50a4afb468ffa1219ee2d315a29808697e2d14c1 Mon Sep 17 00:00:00 2001 From: Marian Csontos Date: Mon, 5 May 2025 17:36:05 +0200 -Subject: [PATCH 7/7] WHATS_NEW_DM: update +Subject: [PATCH 07/47] WHATS_NEW_DM: update +(cherry picked from commit 72f203a02d7f30d5afdaa853a082b2b1d1f56297) --- - WHATS_NEW_DM | 10 ++++++++++ - 1 file changed, 10 insertions(+) + WHATS_NEW_DM | 7 +++++++ + 1 file changed, 7 insertions(+) diff --git a/WHATS_NEW_DM b/WHATS_NEW_DM -index 62ad0a055..0b167ec36 100644 +index 0bbdd1867..d4282ef20 100644 --- a/WHATS_NEW_DM +++ b/WHATS_NEW_DM -@@ -1,3 +1,13 @@ -+Version 1.02.207 - -+================================ -+ -+RHEL9 - 05th May 2025 -+===================== +@@ -1,3 +1,10 @@ ++RHEL9 - 30th September 2025 ++=========================== + Revert Increase DM_UDEV_RULES_VSN to 3 to indicate changed udev rules. + Revert Rename DM_NOSCAN to .DM_NOSCAN so it's not stored in udev db. + Revert Rename DM_SUSPENDED to .DM_SUSPENDED so it's not stored in udev db. + Revert Do not import DM_UDEV_DISABLE_OTHER_RULES_FLAG from db in 10-dm-disk.rules. + - Version 1.02.206 - 05th May 2025 - ================================ - Add support for using regex in selection criteria for string lists. + Version 1.02.207 - 27th June 2025 + ================================= + Escape the escape character itself on JSON report format output. -- -2.49.0 +2.51.0 diff --git a/SOURCES/0008-lvmlockd-fix-hosts-check-for-vgremove.patch b/SOURCES/0008-lvmlockd-fix-hosts-check-for-vgremove.patch deleted file mode 100644 index 2eab959..0000000 --- a/SOURCES/0008-lvmlockd-fix-hosts-check-for-vgremove.patch +++ /dev/null @@ -1,143 +0,0 @@ -From 54d5564f0fc375278c940635c449bdeb24334b71 Mon Sep 17 00:00:00 2001 -From: David Teigland -Date: Wed, 7 May 2025 17:51:01 -0500 -Subject: [PATCH 08/14] lvmlockd: fix hosts check for vgremove - -errors from lock manager were not being considered. -EAGAIN from sanlock should be considered EBUSY. - -(cherry picked from commit 53752ef851d3210e52297ebb4744fdd766c060c6) ---- - daemons/lvmlockd/lvmlockd-core.c | 11 ++++++++--- - daemons/lvmlockd/lvmlockd-dlm.c | 8 ++++++++ - daemons/lvmlockd/lvmlockd-sanlock.c | 26 ++++++++++++++++++++++---- - 3 files changed, 38 insertions(+), 7 deletions(-) - -diff --git a/daemons/lvmlockd/lvmlockd-core.c b/daemons/lvmlockd/lvmlockd-core.c -index c65a3cc39..e4aa91216 100644 ---- a/daemons/lvmlockd/lvmlockd-core.c -+++ b/daemons/lvmlockd/lvmlockd-core.c -@@ -2708,13 +2708,16 @@ static void *lockspace_thread_main(void *arg_in) - rv = lm_hosts(ls, 1); - if (rv) { - /* -+ * rv < 0: error (don't remove) -+ * rv > 0: other hosts in lockspace (cannot remove) -+ * rv = 0: only local host in lockspace (can remove) - * Checking for hosts here in addition to after the - * main loop allows vgremove to fail and be rerun - * after the ls is stopped on other hosts. - */ - log_error("S %s lockspace hosts %d", ls->name, rv); - list_del(&act->list); -- act->result = -EBUSY; -+ act->result = (rv < 0) ? rv : -EBUSY; - add_client_result(act); - continue; - } -@@ -2727,7 +2730,9 @@ static void *lockspace_thread_main(void *arg_in) - if (act->op == LD_OP_BUSY && act->rt == LD_RT_VG) { - log_debug("S %s checking if lockspace is busy", ls->name); - rv = lm_hosts(ls, 0); -- if (rv) -+ if (rv < 0) -+ act->result = rv; -+ else if (rv) - act->result = -EBUSY; - else - act->result = 0; -@@ -2743,7 +2748,7 @@ static void *lockspace_thread_main(void *arg_in) - if (rv) { - log_error("S %s lockspace hosts %d", ls->name, rv); - list_del(&act->list); -- act->result = -EBUSY; -+ act->result = (rv < 0) ? rv : -EBUSY; - add_client_result(act); - continue; - } -diff --git a/daemons/lvmlockd/lvmlockd-dlm.c b/daemons/lvmlockd/lvmlockd-dlm.c -index 72b139170..7529ad327 100644 ---- a/daemons/lvmlockd/lvmlockd-dlm.c -+++ b/daemons/lvmlockd/lvmlockd-dlm.c -@@ -799,6 +799,14 @@ int lm_unlock_dlm(struct lockspace *ls, struct resource *r, - * the stale lockspaces on the others eventually.) - */ - -+/* -+ * On error, returns < 0 -+ * -+ * On success: -+ * If other hosts are found, returns the number. -+ * If no other hosts are found (only ourself), returns 0. -+ */ -+ - int lm_hosts_dlm(struct lockspace *ls, int notify) - { - char ls_nodes_path[PATH_MAX]; -diff --git a/daemons/lvmlockd/lvmlockd-sanlock.c b/daemons/lvmlockd/lvmlockd-sanlock.c -index 1a3982071..d50d0ce4b 100644 ---- a/daemons/lvmlockd/lvmlockd-sanlock.c -+++ b/daemons/lvmlockd/lvmlockd-sanlock.c -@@ -2296,6 +2296,13 @@ int lm_unlock_sanlock(struct lockspace *ls, struct resource *r, - return 0; - } - -+/* -+ * On error, returns < 0 -+ * Else: -+ * If other hosts are found, returns the number. -+ * If no other hosts are found (only ourself), returns 0. -+ */ -+ - int lm_hosts_sanlock(struct lockspace *ls, int notify) - { - struct sanlk_host *hss = NULL; -@@ -2310,14 +2317,25 @@ int lm_hosts_sanlock(struct lockspace *ls, int notify) - return 0; - - rv = sanlock_get_hosts(ls->name, 0, &hss, &hss_count, 0); -+ -+ if (rv == -EAGAIN) { -+ /* -+ * No host info is available yet (perhaps lockspace was -+ * just started so other host state is unknown.) Pretend -+ * there is one other host (busy). -+ */ -+ log_debug("S %s hosts_san no info, retry later", ls->name); -+ return 1; -+ } -+ - if (rv < 0) { - log_error("S %s hosts_san get_hosts error %d", ls->name, rv); -- return 0; -+ return -1; - } - - if (!hss || !hss_count) { - log_error("S %s hosts_san zero hosts", ls->name); -- return 0; -+ return -1; - } - - hs = hss; -@@ -2336,7 +2354,7 @@ int lm_hosts_sanlock(struct lockspace *ls, int notify) - } - - state = hs->flags & SANLK_HOST_MASK; -- if (state == SANLK_HOST_LIVE) -+ if ((state == SANLK_HOST_LIVE) || (state == SANLK_HOST_UNKNOWN)) - found_others++; - hs++; - } -@@ -2358,7 +2376,7 @@ int lm_hosts_sanlock(struct lockspace *ls, int notify) - - if (!found_self) { - log_error("S %s hosts_san self not found others %d", ls->name, found_others); -- return 0; -+ return -1; - } - - return found_others; --- -2.49.0 - diff --git a/SOURCES/0008-lvmlockd-fix-missing-free-in-vg_status.patch b/SOURCES/0008-lvmlockd-fix-missing-free-in-vg_status.patch new file mode 100644 index 0000000..ede382a --- /dev/null +++ b/SOURCES/0008-lvmlockd-fix-missing-free-in-vg_status.patch @@ -0,0 +1,50 @@ +From 8920f236abae6a9e7b15a0b11c1b9d5bad370aae Mon Sep 17 00:00:00 2001 +From: David Teigland +Date: Thu, 26 Jun 2025 13:42:38 -0500 +Subject: [PATCH 08/47] lvmlockd: fix missing free in vg_status + +and add more checking of get_hosts result. + +used by lockd_vg_is_started() for the PR feature. + +(cherry picked from commit 5f0ddd0fd891e769577f6cd3546326f18dbc3bca) +--- + daemons/lvmlockd/lvmlockd-sanlock.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/daemons/lvmlockd/lvmlockd-sanlock.c b/daemons/lvmlockd/lvmlockd-sanlock.c +index 1af3c368f..97f06d115 100644 +--- a/daemons/lvmlockd/lvmlockd-sanlock.c ++++ b/daemons/lvmlockd/lvmlockd-sanlock.c +@@ -2352,7 +2352,7 @@ int lm_unlock_sanlock(struct lockspace *ls, struct resource *r, + + int lm_vg_status_sanlock(struct lockspace *ls, struct action *act) + { +- struct sanlk_host *hs; ++ struct sanlk_host *hs = NULL; + const char *host_state; + int count = 0; + int rv; +@@ -2366,6 +2366,11 @@ int lm_vg_status_sanlock(struct lockspace *ls, struct action *act) + return rv; + } + ++ if (!count || !hs) { ++ log_error("S %s vg_status_san get_hosts empty", ls->name); ++ return -EINVAL; ++ } ++ + act->owner.host_id = (uint32_t)hs->host_id; + act->owner.generation = (uint32_t)hs->generation; + act->owner.timestamp = (uint32_t)hs->timestamp; +@@ -2373,6 +2378,7 @@ int lm_vg_status_sanlock(struct lockspace *ls, struct action *act) + if ((host_state = _host_flags_to_str(hs->flags))) + dm_strncpy(act->owner.state, host_state, OWNER_STATE_SIZE-1); + ++ free(hs); + return 0; + } + +-- +2.51.0 + diff --git a/SOURCES/0009-lvmlockd-add-repair-option-to-reinitialize-sanlock-l.patch b/SOURCES/0009-lvmlockd-add-repair-option-to-reinitialize-sanlock-l.patch new file mode 100644 index 0000000..4d18df6 --- /dev/null +++ b/SOURCES/0009-lvmlockd-add-repair-option-to-reinitialize-sanlock-l.patch @@ -0,0 +1,686 @@ +From 5878a6dc3167e4f9fc4c1dcb04c3dd41e3d4db19 Mon Sep 17 00:00:00 2001 +From: David Teigland +Date: Mon, 30 Jun 2025 12:59:49 -0500 +Subject: [PATCH 09/47] lvmlockd: add repair option to reinitialize sanlock + leases + +If sanlock leases become corrupted, adding --lockopt repair +to the command will let lvmlockd reinitialize them. + +(cherry picked from commit 4bc52d2dc5dee3c57f88d58c3143e8a2f4d44d9f) +--- + configure.ac | 1 + + daemons/lvmlockd/lvmlockd-core.c | 24 +-- + daemons/lvmlockd/lvmlockd-internal.h | 8 +- + daemons/lvmlockd/lvmlockd-sanlock.c | 212 ++++++++++++++++++++++++--- + lib/locking/lvmlockd.c | 69 +++++++-- + lib/locking/lvmlockd.h | 4 + + 6 files changed, 277 insertions(+), 41 deletions(-) + +diff --git a/configure.ac b/configure.ac +index 6fcf6f2b5..11a735af5 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -936,6 +936,7 @@ dnl -- Look for sanlock libraries + AS_IF([test "$BUILD_LOCKDSANLOCK" = "yes"], [ + LOCKDSANLOCK_SUPPORT=370 + PKG_CHECK_EXISTS(libsanlock_client >= 4.0.0, [LOCKDSANLOCK_SUPPORT=400]) ++ PKG_CHECK_EXISTS(libsanlock_client >= 4.1.0, [LOCKDSANLOCK_SUPPORT=410]) + PKG_CHECK_MODULES(LIBSANLOCKCLIENT, libsanlock_client >= 3.7.0, [BUILD_LVMLOCKD="yes"]) + AC_DEFINE_UNQUOTED([LOCKDSANLOCK_SUPPORT], [$LOCKDSANLOCK_SUPPORT], [Define version of sanlock.]) + ]) +diff --git a/daemons/lvmlockd/lvmlockd-core.c b/daemons/lvmlockd/lvmlockd-core.c +index 66a5d5e20..0cb10369a 100644 +--- a/daemons/lvmlockd/lvmlockd-core.c ++++ b/daemons/lvmlockd/lvmlockd-core.c +@@ -1057,7 +1057,7 @@ static void lm_vg_status(struct lockspace *ls, struct action *act) + act->lm_rv = rv; + } + +-static int lm_prepare_lockspace(struct lockspace *ls, struct action *act) ++static int lm_prepare_lockspace(struct lockspace *ls, struct action *act, int repair) + { + uint64_t prev_generation = 0; + int rv = -1; +@@ -1065,7 +1065,7 @@ static int lm_prepare_lockspace(struct lockspace *ls, struct action *act) + if (ls->lm_type == LD_LM_DLM) { + rv = lm_prepare_lockspace_dlm(ls); + } else if (ls->lm_type == LD_LM_SANLOCK) { +- rv = lm_prepare_lockspace_sanlock(ls, &prev_generation); ++ rv = lm_prepare_lockspace_sanlock(ls, &prev_generation, repair); + /* borrowing action.owner to avoid adding another action field */ + if (!rv) + act->owner.generation = (uint32_t)prev_generation; +@@ -1126,14 +1126,14 @@ static int lm_add_resource(struct lockspace *ls, struct resource *r) + + static int lm_lock(struct lockspace *ls, struct resource *r, int mode, struct action *act, + struct val_blk *vb_out, int *retry, struct owner *owner, +- int adopt_only, int adopt_ok) ++ int adopt_only, int adopt_ok, int repair) + { + int rv = -1; + + if (ls->lm_type == LD_LM_DLM) + rv = lm_lock_dlm(ls, r, mode, vb_out, adopt_only, adopt_ok); + else if (ls->lm_type == LD_LM_SANLOCK) +- rv = lm_lock_sanlock(ls, r, mode, vb_out, retry, owner, adopt_only, adopt_ok); ++ rv = lm_lock_sanlock(ls, r, mode, vb_out, retry, owner, adopt_only, adopt_ok, repair); + else if (ls->lm_type == LD_LM_IDM) + rv = lm_lock_idm(ls, r, mode, vb_out, act->lv_uuid, + &act->pvs, adopt_only, adopt_ok); +@@ -1309,7 +1309,8 @@ static int res_lock(struct lockspace *ls, struct resource *r, struct action *act + + rv = lm_lock(ls, r, act->mode, act, &vb, retry, owner, + act->flags & LD_AF_ADOPT_ONLY ? 1 : 0, +- act->flags & LD_AF_ADOPT ? 1 : 0); ++ act->flags & LD_AF_ADOPT ? 1 : 0, ++ act->flags & LD_AF_REPAIR ? 1 : 0); + + if (rv && r->use_vb) + log_debug("%s:%s res_lock rv %d read vb %x %x %u", +@@ -2577,6 +2578,7 @@ static void *lockspace_thread_main(void *arg_in) + int error = 0; + int adopt_only = 0; + int adopt_ok = 0; ++ int repair = 0; + int wait_flag = 0; + int nodelay = 0; + int nocreate; +@@ -2604,6 +2606,8 @@ static void *lockspace_thread_main(void *arg_in) + adopt_ok = 1; + if (add_act->flags & LD_AF_NODELAY) + nodelay = 1; ++ if (add_act->flags & LD_AF_REPAIR) ++ repair = 1; + } + } + pthread_mutex_unlock(&ls->mutex); +@@ -2613,14 +2617,14 @@ static void *lockspace_thread_main(void *arg_in) + adopt_ok = 1; + } + +- log_debug("S %s lm_add_lockspace %s wait %d adopt_only %d adopt_ok %d", +- ls->name, lm_str(ls->lm_type), wait_flag, adopt_only, adopt_ok); ++ log_debug("S %s lm_add_lockspace %s act %d wait %d adopt_only %d adopt_ok %d repair %d", ++ ls->name, lm_str(ls->lm_type), add_act ? 1 : 0, wait_flag, adopt_only, adopt_ok, repair); + + /* + * The prepare step does not wait for anything and is quick; + * it tells us if the parameters are valid and the lm is running. + */ +- error = lm_prepare_lockspace(ls, add_act); ++ error = lm_prepare_lockspace(ls, add_act, repair); + + if (add_act && (!wait_flag || error)) { + /* send initial join result back to client */ +@@ -4789,6 +4793,8 @@ static uint32_t str_to_opts(const char *str) + flags |= LD_AF_DISABLE; + if (strstr(str, "nodelay")) + flags |= LD_AF_NODELAY; ++ if (strstr(str, "repair")) ++ flags |= LD_AF_REPAIR; + + /* FIXME: parse the flag values properly */ + if (strstr(str, "adopt_only")) +@@ -5310,7 +5316,7 @@ skip_pvs_path: + dm_config_destroy(req.cft); + buffer_destroy(&req.buffer); + +- log_debug("recv %s[%d][%u] %s%s%s %s%s %s%s%s%s opts=%x", ++ log_debug("recv %s[%d][%u] %s%s%s %s%s %s%s%s%s opts=0x%x", + cl->name[0] ? cl->name : "client", cl->pid, cl->id, + op_mode_str(act->op, act->mode), act->rt ? "_" : "", rt_str(act->rt), + act->vg_name[0] ? "vg=" : "", +diff --git a/daemons/lvmlockd/lvmlockd-internal.h b/daemons/lvmlockd/lvmlockd-internal.h +index bf40c77f2..7999c2a03 100644 +--- a/daemons/lvmlockd/lvmlockd-internal.h ++++ b/daemons/lvmlockd/lvmlockd-internal.h +@@ -118,6 +118,7 @@ struct client { + #define LD_AF_SH_EXISTS 0x00100000 + #define LD_AF_ADOPT_ONLY 0x00200000 /* adopt orphan or fail */ + #define LD_AF_NODELAY 0x00400000 ++#define LD_AF_REPAIR 0x00800000 + + /* + * Number of times to repeat a lock request after +@@ -209,6 +210,7 @@ struct lockspace { + int8_t lm_type; /* lock manager: LM_DLM, LM_SANLOCK */ + void *lm_data; + uint32_t host_id; ++ uint64_t generation; + uint64_t free_lock_offset; /* for sanlock, start search for free lock here */ + struct pvs pvs; /* for idm: PV list */ + +@@ -561,13 +563,13 @@ int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_ar + int lm_init_lv_sanlock(struct lockspace *ls, char *ls_name, char *vg_name, char *lv_name, char *vg_args, char *lv_args, char *prev_args); + int lm_free_lv_sanlock(struct lockspace *ls, struct resource *r); + int lm_rename_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_args); +-int lm_prepare_lockspace_sanlock(struct lockspace *ls, uint64_t *prev_generation); ++int lm_prepare_lockspace_sanlock(struct lockspace *ls, uint64_t *prev_generation, int repair); + int lm_add_lockspace_sanlock(struct lockspace *ls, int adopt_only, int adopt_ok, int nodelay); + int lm_rem_lockspace_sanlock(struct lockspace *ls, int free_vg); + int lm_add_resource_sanlock(struct lockspace *ls, struct resource *r); + int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode, + struct val_blk *vb_out, int *retry, struct owner *owner, +- int adopt_only, int adopt_ok); ++ int adopt_only, int adopt_ok, int repair); + int lm_convert_sanlock(struct lockspace *ls, struct resource *r, + int ld_mode, uint32_t r_version); + int lm_unlock_sanlock(struct lockspace *ls, struct resource *r, +@@ -610,7 +612,7 @@ static inline int lm_rename_vg_sanlock(char *ls_name, char *vg_name, uint32_t fl + return -1; + } + +-static inline int lm_prepare_lockspace_sanlock(struct lockspace *ls, uint64_t *prev_generation) ++static inline int lm_prepare_lockspace_sanlock(struct lockspace *ls, uint64_t *prev_generation, int repair) + { + return -1; + } +diff --git a/daemons/lvmlockd/lvmlockd-sanlock.c b/daemons/lvmlockd/lvmlockd-sanlock.c +index 97f06d115..ce5953faf 100644 +--- a/daemons/lvmlockd/lvmlockd-sanlock.c ++++ b/daemons/lvmlockd/lvmlockd-sanlock.c +@@ -218,6 +218,18 @@ int lm_data_size_sanlock(void) + + static uint64_t daemon_test_lv_count; + ++static void _fclose(FILE *fp, char *name) ++{ ++ if (fclose(fp)) ++ log_warn("fclose error %d %s", errno, name ?: ""); ++} ++ ++static void _close(int fd) ++{ ++ if (close(fd)) ++ log_warn("close error %d fd %d", errno, fd); ++} ++ + /* + * Copy a null-terminated string "str" into a fixed + * size struct field "buf" which is not null terminated. +@@ -308,14 +320,74 @@ static int read_host_id_file(void) + break; + } + } +- if (fclose(file)) +- log_debug("Failed to fclose host id file %s (%s).", +- daemon_host_id_file, strerror(errno)); ++ _fclose(file, (char *)daemon_host_id_file); + out: + log_debug("host_id %d from %s", host_id, daemon_host_id_file); + return host_id; + } + ++static int read_info_file(struct lockspace *ls, uint32_t *host_id, uint64_t *generation, int *sector_size, int *align_size) ++{ ++ char line[MAX_LINE]; ++ char path[PATH_MAX] = { 0 }; ++ FILE *fp; ++ ++ if (dm_snprintf(path, PATH_MAX-1, "/var/lib/lvm/lvmlockd_info_%s", ls->vg_name) < 0) ++ return -1; ++ ++ if (!(fp = fopen(path, "r"))) { ++ log_debug("Failed to open info file"); ++ return -1; ++ } ++ ++ while (fgets(line, sizeof(line), fp)) { ++ if (line[0] == '#') ++ continue; ++ if (!strncmp(line, "host_id ", 8)) { ++ sscanf(line, "host_id %u", host_id); ++ } else if (!strncmp(line, "generation ", 11)) { ++ sscanf(line, "generation %llu", (unsigned long long *)generation); ++ } else if (!strncmp(line, "sector_size ", 12)) { ++ sscanf(line, "sector_size %d", sector_size); ++ } else if (!strncmp(line, "align_size ", 11)) { ++ sscanf(line, "align_size %d", align_size); ++ } ++ } ++ ++ _fclose(fp, path); ++ log_debug("info file: read %u %llu %d %d", *host_id, (unsigned long long)*generation, *sector_size, *align_size); ++ return 0; ++} ++ ++static int write_info_file(struct lockspace *ls) ++{ ++ struct lm_sanlock *lms = (struct lm_sanlock *)ls->lm_data; ++ char path[PATH_MAX] = { 0 }; ++ FILE *fp; ++ time_t t; ++ ++ if (dm_snprintf(path, PATH_MAX-1, "/var/lib/lvm/lvmlockd_info_%s", ls->vg_name) < 0) ++ return -1; ++ ++ if (!(fp = fopen(path, "w"))) { ++ log_debug("Failed to create info file"); ++ return -1; ++ } ++ ++ fprintf(fp, "# vg %s %s created %s", ls->vg_name, ls->vg_uuid, ctime(&t)); ++ fprintf(fp, "host_id %u\n", ls->host_id); ++ fprintf(fp, "generation %llu\n", (unsigned long long)ls->generation); ++ fprintf(fp, "sector_size %d\n", lms->sector_size); ++ fprintf(fp, "align_size %d\n", lms->align_size); ++ ++ if (fflush(fp)) ++ log_warn("Failed to write/flush %s", path); ++ _fclose(fp, path); ++ ++ log_debug("info file: wrote %u %llu %d %d", ls->host_id, (unsigned long long)ls->generation, lms->sector_size, lms->align_size); ++ return 0; ++} ++ + /* Prepare valid /dev/mapper/vgname-lvname with all the mangling */ + static int build_dm_path(char *path, size_t path_len, + const char *vg_name, const char *lv_name) +@@ -370,7 +442,7 @@ static void _read_sysfs_size(dev_t devno, const char *name, uint64_t *val) + if (strlen(buf)) + *val = strtoull(buf, NULL, 0); + out: +- (void)fclose(fp); ++ _fclose(fp, path); + } + + /* Select sector/align size for a new VG based on what the device reports for +@@ -479,6 +551,7 @@ static int _lease_corrupt_error(int rv) + { + if (rv == SANLK_LEADER_MAGIC || + rv == SANLK_LEADER_VERSION || ++ rv == SANLK_LEADER_DIFF || + rv == SANLK_LEADER_LOCKSPACE || + rv == SANLK_LEADER_RESOURCE || + rv == SANLK_LEADER_CHECKSUM || +@@ -509,8 +582,10 @@ static int read_lockspace_info(char *path, uint32_t host_id, int *sector_size, i + #endif + rv = sanlock_read_lockspace(&ss, 0, &io_timeout); + +- if (_lease_corrupt_error(rv)) ++ if (_lease_corrupt_error(rv)) { ++ log_error("read_lockspace_info %s %u corrupt lease error %d", path, host_id, rv); + return -ELOCKREPAIR; ++ } + + if (rv < 0) { + log_error("read_lockspace_info %s %u error %d", path, host_id, rv); +@@ -1471,7 +1546,7 @@ int lm_find_free_lock_sanlock(struct lockspace *ls, uint64_t lv_size_bytes) + * This should also not create any major problems. + */ + +-int lm_prepare_lockspace_sanlock(struct lockspace *ls, uint64_t *prev_generation) ++int lm_prepare_lockspace_sanlock(struct lockspace *ls, uint64_t *prev_generation, int repair) + { + struct stat st; + struct lm_sanlock *lms = NULL; +@@ -1486,6 +1561,7 @@ int lm_prepare_lockspace_sanlock(struct lockspace *ls, uint64_t *prev_generation + int sector_size = 0; + int align_size = 0; + int align_mb = 0; ++ int retries = 0; + int gl_found; + int ret, rv; + +@@ -1502,6 +1578,8 @@ int lm_prepare_lockspace_sanlock(struct lockspace *ls, uint64_t *prev_generation + memset(killargs, 0, sizeof(killargs)); + snprintf(killargs, SANLK_PATH_LEN, "--kill %s", ls->vg_name); + ++ log_debug("S %s prepare_lockspace_san host_id %u repair %d", ls->name, ls->host_id, repair); ++ + rv = check_args_version(ls->vg_args, VG_LOCK_ARGS_MAJOR); + if (rv < 0) { + ret = -EARGS; +@@ -1602,7 +1680,63 @@ int lm_prepare_lockspace_sanlock(struct lockspace *ls, uint64_t *prev_generation + goto fail; + } + ++ repair_retry: ++ sector_size = 0; ++ align_size = 0; ++ + rv = read_lockspace_info(disk_path, lms->ss.host_id, §or_size, &align_size, &align_mb, &ss_flags, &rs_flags, &hs); ++ ++#if LOCKDSANLOCK_SUPPORT >= 410 ++ if ((rv == -ELOCKREPAIR) && repair && !retries) { ++ uint64_t generation = 0; ++ uint32_t host_id = 0; ++ ++ rv = read_info_file(ls, &host_id, &generation, §or_size, &align_size); ++ if (rv < 0) { ++ log_error("S %s prepare_lockspace_san cannot repair lockspace no info file", lsname); ++ ret = -EINVAL; ++ } ++ ++ if (host_id != lms->ss.host_id) { ++ log_error("S %s prepare_lockspace_san cannot repair lockspace other info host_id", lsname); ++ ret = -EINVAL; ++ } ++ ++ hs.generation = generation; ++ ++ if (sector_size == 512) { ++ lms->ss.flags |= SANLK_LSF_SECTOR512; ++ lms->ss.flags |= SANLK_LSF_ALIGN1M; ++ } else if (sector_size == 4096) { ++ lms->ss.flags |= SANLK_LSF_SECTOR4K; ++ if (align_size == ONE_MB) ++ lms->ss.flags |= SANLK_LSF_ALIGN1M; ++ else if (align_size == 2 * ONE_MB) ++ lms->ss.flags |= SANLK_LSF_ALIGN2M; ++ else if (align_size == 4 * ONE_MB) ++ lms->ss.flags |= SANLK_LSF_ALIGN4M; ++ else if (align_size == 8 * ONE_MB) ++ lms->ss.flags |= SANLK_LSF_ALIGN8M; ++ } else { ++ log_error("S %s prepare_lockspace_san cannot repair lockspace invalid sector_size", lsname); ++ ret = -EINVAL; ++ } ++ ++ log_debug("S %s prepare_lockspace_san repair host %u lease", lsname, host_id); ++ ++ rv = sanlock_init_lockspace_host(&lms->ss, NULL, generation, 0, 0, 0); ++ if (rv < 0) { ++ log_error("S %s prepare_lockspace_san repair host %u lease error %d", lsname, host_id, rv); ++ ret = -EMANAGER; ++ } ++ retries = 1; ++ goto repair_retry; ++ } ++#else ++ if ((rv == -ELOCKREPAIR) && repair && !retries) ++ log_debug("S %s prepare_lockspace_san sanlock does not support repair.", lsname); ++#endif ++ + if (rv < 0) { + log_error("S %s prepare_lockspace_san cannot read lockspace info %d", lsname, rv); + ret = -EMANAGER; +@@ -1675,7 +1809,7 @@ out: + + fail: + if (lms && lms->sock) +- close(lms->sock); ++ _close(lms->sock); + free(lms); + return ret; + } +@@ -1683,7 +1817,9 @@ fail: + int lm_add_lockspace_sanlock(struct lockspace *ls, int adopt_only, int adopt_ok, int nodelay) + { + struct lm_sanlock *lms = (struct lm_sanlock *)ls->lm_data; ++ struct sanlk_host *hs = NULL; + uint32_t flags = 0; ++ int count = 0; + int rv; + + if (daemon_test) { +@@ -1710,6 +1846,33 @@ int lm_add_lockspace_sanlock(struct lockspace *ls, int adopt_only, int adopt_ok, + goto fail; + } + ++ rv = sanlock_get_hosts(ls->name, 0, &hs, &count, SANLK_GET_HOST_LOCAL); ++ if (rv < 0) { ++ log_error("S %s add_lockspace_san add_lockspace get_host error %d", ls->name, rv); ++ goto fail_rem; ++ } ++ ++ if (!count || !hs) { ++ log_error("S %s add_lockspace_san add_lockspace get_host empty", ls->name); ++ goto fail_rem; ++ } ++ ++ if ((uint32_t)hs->host_id != ls->host_id) { ++ log_error("S %s add_lockspace_san add_lockspace get_host invalid host_id", ls->name); ++ goto fail_rem; ++ } ++ ++ if (!hs->generation) { ++ log_error("S %s add_lockspace_san add_lockspace get_host zero generation", ls->name); ++ goto fail_rem; ++ } ++ ++ ls->generation = hs->generation; ++ ++ free(hs); ++ ++ write_info_file(ls); ++ + /* + * Don't let the lockspace be cleanly released if orphan locks + * exist, because the orphan locks are still protecting resources +@@ -1721,17 +1884,17 @@ int lm_add_lockspace_sanlock(struct lockspace *ls, int adopt_only, int adopt_ok, + rv = sanlock_set_config(ls->name, 0, SANLK_CONFIG_USED_BY_ORPHANS, NULL); + if (rv < 0) { + log_error("S %s add_lockspace_san set_config error %d", ls->name, rv); +- sanlock_rem_lockspace(&lms->ss, 0); +- goto fail; ++ goto fail_rem; + } + + out: + log_debug("S %s add_lockspace_san done", ls->name); + return 0; + ++fail_rem: ++ sanlock_rem_lockspace(&lms->ss, 0); + fail: +- if (close(lms->sock)) +- log_error("failed to close sanlock daemon socket connection"); ++ _close(lms->sock); + free(lms); + ls->lm_data = NULL; + return rv; +@@ -1767,8 +1930,7 @@ int lm_rem_lockspace_sanlock(struct lockspace *ls, int free_vg) + } + } + +- if (close(lms->sock)) +- log_error("failed to close sanlock daemon socket connection"); ++ _close(lms->sock); + out: + free(lms); + ls->lm_data = NULL; +@@ -1845,7 +2007,7 @@ static const char *_host_flags_to_str(uint32_t flags) + + int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode, + struct val_blk *vb_out, int *retry, struct owner *owner, +- int adopt_only, int adopt_ok) ++ int adopt_only, int adopt_ok, int repair) + { + struct lm_sanlock *lms = (struct lm_sanlock *)ls->lm_data; + struct rd_sanlock *rds = (struct rd_sanlock *)r->lm_data; +@@ -1857,6 +2019,7 @@ int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode, + uint32_t flags = 0; + struct val_blk vb = { 0 }; + int added = 0; ++ int retries = 0; + int rv; + + if (!r->lm_init) { +@@ -1956,6 +2119,8 @@ int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode, + memset(&opt, 0, sizeof(opt)); + sprintf(opt.owner_name, "%s", "lvmlockd"); + ++ repair_retry: ++ + #if LOCKDSANLOCK_SUPPORT >= 400 + rv = sanlock_acquire2(lms->sock, -1, flags, rs, &opt, &owner_host, &owner_name); + #else +@@ -2068,9 +2233,20 @@ int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode, + return -EIOTIMEOUT; + } + ++ if (_lease_corrupt_error(rv) && repair && !retries) { ++ log_debug("%s:%s lock_san acquire lease_corrupt %d repair", ls->name, r->name, rv); ++ ++ rv = sanlock_write_resource(rs, 0, 0, 0); ++ if (rv < 0) { ++ log_error("%s:%s lock_san acquire lease repair write_resource error %d", ls->name, r->name, rv); ++ return rv; ++ } ++ retries = 1; ++ goto repair_retry; ++ } ++ + if (rv < 0) { +- log_error("%s:%s lock_san acquire error %d", +- ls->name, r->name, rv); ++ log_error("%s:%s lock_san acquire error %d", ls->name, r->name, rv); + + /* if the gl has been disabled, remove and free the gl resource */ + if ((rv == SANLK_LEADER_RESOURCE) && (r->type == LD_RT_GL)) { +@@ -2094,8 +2270,10 @@ int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode, + rv == SANLK_DBLOCK_WRITE) + return -ELOCKIO; + +- if (_lease_corrupt_error(rv)) ++ if (_lease_corrupt_error(rv)) { ++ log_debug("%s:%s lock_san lease corrupt repair %d retries %d", ls->name, r->name, repair, retries); + return -ELOCKREPAIR; ++ } + + /* + * The sanlock lockspace can disappear if the lease storage fails, +diff --git a/lib/locking/lvmlockd.c b/lib/locking/lvmlockd.c +index f86007858..68dea52e0 100644 +--- a/lib/locking/lvmlockd.c ++++ b/lib/locking/lvmlockd.c +@@ -1466,11 +1466,17 @@ int lockd_start_vg(struct cmd_context *cmd, struct volume_group *vg, int *exists + + if ((cmd->lockopt & LOCKOPT_NODELAY) || + (cmd->lockopt & LOCKOPT_ADOPTLS) || +- (cmd->lockopt & LOCKOPT_ADOPT)) { +- (void) dm_snprintf(opt_buf, sizeof(opt_buf), "%s%s%s", +- (cmd->lockopt & LOCKOPT_NODELAY) ? "nodelay," : "", +- (cmd->lockopt & LOCKOPT_ADOPTLS) ? "adopt_only" : "", +- (cmd->lockopt & LOCKOPT_ADOPT) ? "adopt" : ""); ++ (cmd->lockopt & LOCKOPT_ADOPT) || ++ (cmd->lockopt & LOCKOPT_REPAIRVG) || ++ (cmd->lockopt & LOCKOPT_REPAIR)) { ++ if (dm_snprintf(opt_buf, sizeof(opt_buf), "%s%s%s%s", ++ (cmd->lockopt & LOCKOPT_NODELAY) ? "nodelay," : "", ++ (cmd->lockopt & LOCKOPT_ADOPTLS) ? "adopt_only," : "", ++ (cmd->lockopt & LOCKOPT_ADOPT) ? "adopt," : "", ++ (cmd->lockopt & (LOCKOPT_REPAIR|LOCKOPT_REPAIRVG)) ? "repair" : "") < 0) { ++ log_error("Options string too long %x", cmd->lockopt); ++ return 0; ++ } + opts = opt_buf; + } + +@@ -1967,6 +1973,7 @@ out: + int lockd_global(struct cmd_context *cmd, const char *def_mode) + { + struct owner owner = { 0 }; ++ char opt_buf[64] = {}; + const char *mode = NULL; + const char *opts = NULL; + uint32_t lockd_flags; +@@ -1996,10 +2003,19 @@ int lockd_global(struct cmd_context *cmd, const char *def_mode) + return 0; + } + +- if (cmd->lockopt & LOCKOPT_ADOPTGL) +- opts = "adopt_only"; +- else if (cmd->lockopt & LOCKOPT_ADOPT) +- opts = "adopt"; ++ if ((cmd->lockopt & LOCKOPT_ADOPTGL) || ++ (cmd->lockopt & LOCKOPT_ADOPT) || ++ (cmd->lockopt & LOCKOPT_REPAIRGL) || ++ (cmd->lockopt & LOCKOPT_REPAIR)) { ++ if (dm_snprintf(opt_buf, sizeof(opt_buf), "%s%s%s", ++ (cmd->lockopt & LOCKOPT_ADOPTGL) ? "adopt_only" : "", ++ (cmd->lockopt & LOCKOPT_ADOPT) ? "adopt" : "", ++ (cmd->lockopt & (LOCKOPT_REPAIR|LOCKOPT_REPAIRGL)) ? "repair" : "") < 0) { ++ log_error("Options string too long %x", cmd->lockopt); ++ return 0; ++ } ++ opts = opt_buf; ++ } + + if (!strcmp(mode, "sh") && cmd->lockd_global_ex) + return 1; +@@ -2255,6 +2271,7 @@ int lockd_vg(struct cmd_context *cmd, const char *vg_name, const char *def_mode, + uint32_t flags, uint32_t *lockd_state) + { + struct owner owner = { 0 }; ++ char opt_buf[64] = {}; + const char *mode = NULL; + const char *opts = NULL; + uint32_t lockd_flags; +@@ -2332,6 +2349,20 @@ int lockd_vg(struct cmd_context *cmd, const char *vg_name, const char *def_mode, + else if (cmd->lockopt & LOCKOPT_ADOPT) + opts = "adopt"; + ++ if ((cmd->lockopt & LOCKOPT_ADOPTVG) || ++ (cmd->lockopt & LOCKOPT_ADOPT) || ++ (cmd->lockopt & LOCKOPT_REPAIRVG) || ++ (cmd->lockopt & LOCKOPT_REPAIR)) { ++ if (dm_snprintf(opt_buf, sizeof(opt_buf), "%s%s%s", ++ (cmd->lockopt & LOCKOPT_ADOPTVG) ? "adopt_only" : "", ++ (cmd->lockopt & LOCKOPT_ADOPT) ? "adopt" : "", ++ (cmd->lockopt & (LOCKOPT_REPAIR|LOCKOPT_REPAIRVG)) ? "repair" : "") < 0) { ++ log_error("Options string too long %x.", cmd->lockopt); ++ return 0; ++ } ++ opts = opt_buf; ++ } ++ + if (!strcmp(mode, "ex")) + *lockd_state |= LDST_EX; + +@@ -2792,11 +2823,17 @@ int lockd_lv_name(struct cmd_context *cmd, struct volume_group *vg, + + if ((flags & LDLV_PERSISTENT) || + (cmd->lockopt & LOCKOPT_ADOPTLV) || +- (cmd->lockopt & LOCKOPT_ADOPT)) { +- (void) dm_snprintf(opt_buf, sizeof(opt_buf), "%s%s%s", ++ (cmd->lockopt & LOCKOPT_ADOPT) || ++ (cmd->lockopt & LOCKOPT_REPAIRLV) || ++ (cmd->lockopt & LOCKOPT_REPAIR)) { ++ if (dm_snprintf(opt_buf, sizeof(opt_buf), "%s%s%s%s", + (flags & LDLV_PERSISTENT) ? "persistent," : "", + (cmd->lockopt & LOCKOPT_ADOPTLV) ? "adopt_only" : "", +- (cmd->lockopt & LOCKOPT_ADOPT) ? "adopt" : ""); ++ (cmd->lockopt & LOCKOPT_ADOPT) ? "adopt" : "", ++ (cmd->lockopt & (LOCKOPT_REPAIR|LOCKOPT_REPAIRLV)) ? "repair" : "") < 0) { ++ log_error("Options string too long %x.", cmd->lockopt); ++ return 0; ++ } + opts = opt_buf; + } + +@@ -4397,6 +4434,14 @@ void lockd_lockopt_get_flags(const char *str, uint32_t *flags) + *flags |= LOCKOPT_ADOPT; + else if (!strcmp(argv[i], "nodelay")) + *flags |= LOCKOPT_NODELAY; ++ else if (!strcmp(argv[i], "repair")) ++ *flags |= LOCKOPT_REPAIR; ++ else if (!strcmp(argv[i], "repairgl")) ++ *flags |= LOCKOPT_REPAIRGL; ++ else if (!strcmp(argv[i], "repairvg")) ++ *flags |= LOCKOPT_REPAIRVG; ++ else if (!strcmp(argv[i], "repairlv")) ++ *flags |= LOCKOPT_REPAIRLV; + else + log_warn("Ignoring unknown lockopt value: %s", argv[i]); + } +diff --git a/lib/locking/lvmlockd.h b/lib/locking/lvmlockd.h +index 85295852c..18f01cd23 100644 +--- a/lib/locking/lvmlockd.h ++++ b/lib/locking/lvmlockd.h +@@ -58,6 +58,10 @@ + #define LOCKOPT_ADOPTLV 0x00001000 + #define LOCKOPT_ADOPT 0x00002000 + #define LOCKOPT_NODELAY 0x00004000 ++#define LOCKOPT_REPAIR 0x00008000 ++#define LOCKOPT_REPAIRGL 0x00010000 ++#define LOCKOPT_REPAIRVG 0x00020000 ++#define LOCKOPT_REPAIRLV 0x00040000 + + #ifdef LVMLOCKD_SUPPORT + +-- +2.51.0 + diff --git a/SOURCES/0009-lvmlockd-fix-sanlock_release-for-vgremove.patch b/SOURCES/0009-lvmlockd-fix-sanlock_release-for-vgremove.patch deleted file mode 100644 index 6bef1a7..0000000 --- a/SOURCES/0009-lvmlockd-fix-sanlock_release-for-vgremove.patch +++ /dev/null @@ -1,38 +0,0 @@ -From 0b375ab5f49c4eea0c705ef8e27e94a366b0f6d6 Mon Sep 17 00:00:00 2001 -From: David Teigland -Date: Thu, 8 May 2025 10:54:50 -0500 -Subject: [PATCH 09/14] lvmlockd: fix sanlock_release for vgremove - -incorrect data was being copied to lease structs passed -to sanlock_release(), making the lease removal fail. - -(cherry picked from commit 88910c200f9e24a454dc9fcbf39c2df1d4887f3b) ---- - daemons/lvmlockd/lvmlockd-sanlock.c | 7 +++++-- - 1 file changed, 5 insertions(+), 2 deletions(-) - -diff --git a/daemons/lvmlockd/lvmlockd-sanlock.c b/daemons/lvmlockd/lvmlockd-sanlock.c -index d50d0ce4b..b17cbad7e 100644 ---- a/daemons/lvmlockd/lvmlockd-sanlock.c -+++ b/daemons/lvmlockd/lvmlockd-sanlock.c -@@ -2192,12 +2192,15 @@ static int release_rename(struct lockspace *ls, struct resource *r) - if (!res_args) - return -ENOMEM; - -- memcpy(&rd1, rds, sizeof(struct rd_sanlock)); -- memcpy(&rd2, rds, sizeof(struct rd_sanlock)); -+ memcpy(&rd1, &rds->rs, sizeof(struct rd_sanlock)); -+ memcpy(&rd2, &rds->rs, sizeof(struct rd_sanlock)); - - res1 = (struct sanlk_resource *)&rd1; - res2 = (struct sanlk_resource *)&rd2; - -+ if (memcmp(res1->name, r->name, SANLK_NAME_LEN)) -+ log_error("%s:%s unlock_san release rename bad name %.48s", ls->name, r->name, res1->name); -+ - strcpy_name_len(res2->name, "invalid_removed", SANLK_NAME_LEN); - - res_args[0] = res1; --- -2.49.0 - diff --git a/SOURCES/0010-raid-count-or-clear-transiently-failed-devices.patch b/SOURCES/0010-raid-count-or-clear-transiently-failed-devices.patch deleted file mode 100644 index 7917805..0000000 --- a/SOURCES/0010-raid-count-or-clear-transiently-failed-devices.patch +++ /dev/null @@ -1,460 +0,0 @@ -From ad632cf9f19f3b8efbcf087cbf60527160ba5fec Mon Sep 17 00:00:00 2001 -From: Heinz Mauelshagen -Date: Tue, 5 Nov 2024 18:33:19 +0100 -Subject: [PATCH 10/14] raid: count or clear transiently failed devices - -Count or clear transiently failed devices as of dm-raid superblocks. -Updated debuging. -Use lvconvert --repair to repair transiently failed legs. -Activating all 'meta' LVs with single sync_local_dev_names(). -Using proper DM path for meta LV. - -Modified-by: zkabelac@redhat.com -(cherry picked from commit 03d8661657bb3d1cb5dd764f3a450a8211f892e6) ---- - device_mapper/Makefile | 1 + - device_mapper/all.h | 1 + - device_mapper/raid/raid_parser.c | 164 ++++++++++++++++++++++++++++ - device_mapper/raid/target.h | 23 ++++ - lib/activate/activate.h | 2 + - lib/metadata/raid_manip.c | 179 ++++++++++++++++++++++++++++++- - 6 files changed, 369 insertions(+), 1 deletion(-) - create mode 100644 device_mapper/raid/raid_parser.c - create mode 100644 device_mapper/raid/target.h - -diff --git a/device_mapper/Makefile b/device_mapper/Makefile -index b1aa53c36..4dfcd4f12 100644 ---- a/device_mapper/Makefile -+++ b/device_mapper/Makefile -@@ -25,6 +25,7 @@ DEVICE_MAPPER_SOURCE=\ - device_mapper/libdm-targets.c \ - device_mapper/libdm-timestamp.c \ - device_mapper/mm/pool.c \ -+ device_mapper/raid/raid_parser.c \ - device_mapper/regex/matcher.c \ - device_mapper/regex/parse_rx.c \ - device_mapper/regex/ttree.c \ -diff --git a/device_mapper/all.h b/device_mapper/all.h -index 91c085e76..97279c10b 100644 ---- a/device_mapper/all.h -+++ b/device_mapper/all.h -@@ -19,6 +19,7 @@ - - #include "base/data-struct/list.h" - #include "base/data-struct/hash.h" -+#include "raid/target.h" - #include "vdo/target.h" - - #include -diff --git a/device_mapper/raid/raid_parser.c b/device_mapper/raid/raid_parser.c -new file mode 100644 -index 000000000..adef7bb6c ---- /dev/null -+++ b/device_mapper/raid/raid_parser.c -@@ -0,0 +1,164 @@ -+/* -+ * Copyright (C) 2024 Red Hat, Inc. All rights reserved. -+ * -+ * This file is part of the device-mapper userspace tools. -+ * -+ * 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 Lesser General Public License v.2.1. -+ * -+ * You should have received a copy of the GNU Lesser 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 -+ */ -+ -+/* -+ * Support counting number of failed device bits in dm-raid superblock bit arrays or clear them out. -+ */ -+ -+#include "device_mapper/misc/dmlib.h" -+#include "device_mapper/all.h" -+#include "device_mapper/raid/target.h" -+#include -+#include -+ -+/* Copied/derived from kernel's drivers/md/dm-raid.c so this is prone to out-of-sync (factor out to header file?). */ -+#define MAX_RAID_DEVICES 253 /* md-raid kernel limit? */ -+#define UINT64_BITS (sizeof(uint64_t) * 8) -+#define DISKS_ARRAY_ELEMS ((MAX_RAID_DEVICES + (UINT64_BITS - 1)) / UINT64_BITS) -+#define DM_RAID_SB_MAGIC 0x446D5264 /* "DmRd" */ -+#define FEATURE_FLAG_SUPPORTS_V190 0x1 /* Supports extended superblock */ -+ -+/* RAID superblock at beginning of rmeta SubLVs trimmed down to mandatory members. */ -+struct dm_raid_superblock { -+ __le32 magic; /* "DmRd" */ -+ __le32 compat_features; /* Used to indicate compatible features (like 1.9.0 ondisk metadata extension) */ -+ __le32 dummy[4]; -+ __le64 failed_devices; /* Pre 1.9.0 part of bit field of devices to */ -+ /* indicate device failures (see extension below) */ -+ __le32 dummy1[7]; -+ -+ /******************************************************************** -+ * BELOW FOLLOW V1.9.0 EXTENSIONS TO THE PRISTINE SUPERBLOCK FORMAT!!! -+ * -+ * FEATURE_FLAG_SUPPORTS_V190 in the compat_features member indicates that those exist -+ */ -+ __le32 flags; /* Flags defining array states for reshaping */ -+ __le32 dummy2[14]; -+ __le64 extended_failed_devices[DISKS_ARRAY_ELEMS - 1]; -+ -+ __le32 dummy3; -+ /* Always set rest up to logical block size to 0 when writing ... */ -+} __packed; -+/* END: Copied from ... */ -+ -+/* Superblock I/O buffer size to be able to Cope with 4K native devices... */ -+#define SB_BUFSZ 4096 -+ -+static size_t _get_sb_size(const struct dm_raid_superblock *sb) -+{ -+ return (FEATURE_FLAG_SUPPORTS_V190 & le32toh(sb->compat_features)) ? -+ sizeof(*sb) : ((char *) &sb->flags - (char *) sb); -+} -+ -+static uint32_t _hweight64(__le64 v) -+{ -+ uint32_t r = 0; -+ -+ while (v) { -+ r += v & 1; -+ v >>= 1; -+ } -+ -+ return r; -+} -+ -+static uint32_t _hweight_failed(struct dm_raid_superblock *sb) -+{ -+ uint32_t r = _hweight64(sb->failed_devices); -+ -+ if (_get_sb_size(sb) == sizeof(*sb)) { -+ size_t i = DM_ARRAY_SIZE(sb->extended_failed_devices); -+ -+ while (i--) -+ r = max(r, _hweight64(sb->extended_failed_devices[i])); -+ } -+ -+ return r; -+} -+ -+static void _clear_failed_devices(struct dm_raid_superblock *sb) -+{ -+ -+ sb->failed_devices = 0; -+ -+ if (_get_sb_size(sb) == sizeof(*sb)) -+ memset(sb->extended_failed_devices, 0, sizeof(sb->extended_failed_devices)); -+} -+ -+static int _count_or_clear_failed_devices(const char *dev_path, bool clear, uint32_t *nr_failed) -+{ -+ struct dm_raid_superblock *sb = NULL; -+ size_t sz; -+ int fd, r = 0; -+ -+ if (posix_memalign((void *) &sb, SB_BUFSZ, SB_BUFSZ)) { -+ log_sys_error("Failed to allocate RAID superblock buffer", dev_path); -+ return 0; -+ } -+ -+ fd = open(dev_path, O_EXCL | ((clear) ? O_RDWR : O_RDONLY) | O_DIRECT); -+ if (fd < 0) { -+ log_sys_error("Failed to open RAID metadata volume", dev_path); -+ goto out; -+ } -+ -+ if (read(fd, sb, SB_BUFSZ) != SB_BUFSZ) { -+ log_sys_error("Failed to read RAID metadata volume", dev_path); -+ goto out; -+ } -+ -+ /* FIXME: big endian??? */ -+ if (sb->magic != htobe32(DM_RAID_SB_MAGIC)) { -+ log_error("No RAID signature on %s.", dev_path); -+ goto out; -+ } -+ -+ if (nr_failed) -+ *nr_failed = _hweight_failed(sb); -+ -+ if (clear) { -+ if (lseek(fd, 0, SEEK_SET) < 0) { -+ log_sys_error("Failed to seek RAID metadata volume", dev_path); -+ goto out; -+ } -+ -+ sz = _get_sb_size(sb); -+ memset((void *)((char *) sb + sz), 0, SB_BUFSZ - sz); -+ _clear_failed_devices(sb); -+ if (write(fd, sb, SB_BUFSZ) != SB_BUFSZ) { -+ log_sys_error("Failed to clear RAID metadata volume", dev_path); -+ goto out; -+ } -+ } -+ -+ r = 1; -+ -+out: -+ if ((fd >= 0) && close(fd)) -+ log_sys_debug("close", dev_path); -+ -+ free(sb); -+ -+ return r; -+} -+ -+int dm_raid_count_failed_devices(const char *dev_path, uint32_t *nr_failed) -+{ -+ return _count_or_clear_failed_devices(dev_path, false, nr_failed); -+} -+ -+int dm_raid_clear_failed_devices(const char *dev_path, uint32_t *nr_failed) -+{ -+ return _count_or_clear_failed_devices(dev_path, true, nr_failed); -+} -diff --git a/device_mapper/raid/target.h b/device_mapper/raid/target.h -new file mode 100644 -index 000000000..3e3ec024c ---- /dev/null -+++ b/device_mapper/raid/target.h -@@ -0,0 +1,23 @@ -+/* -+ * Copyright (C) 2024 Red Hat, Inc. All rights reserved. -+ * -+ * This file is part of the device-mapper userspace tools. -+ * -+ * 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 Lesser General Public License v.2.1. -+ * -+ * You should have received a copy of the GNU Lesser 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 -+ */ -+ -+#ifndef DEVICE_MAPPER_RAID_TARGET_H -+#define DEVICE_MAPPER_RAID_TARGET_H -+ -+#include -+ -+int dm_raid_count_failed_devices(const char *dev_path, uint32_t *nr_failed); -+int dm_raid_clear_failed_devices(const char *dev_path, uint32_t *nr_failed); -+ -+#endif -diff --git a/lib/activate/activate.h b/lib/activate/activate.h -index bd30e2655..155936135 100644 ---- a/lib/activate/activate.h -+++ b/lib/activate/activate.h -@@ -197,6 +197,8 @@ int lv_raid_mismatch_count(const struct logical_volume *lv, uint64_t *cnt); - int lv_raid_sync_action(const struct logical_volume *lv, char **sync_action); - int lv_raid_message(const struct logical_volume *lv, const char *msg); - int lv_raid_status(const struct logical_volume *lv, struct lv_status_raid **status); -+int lv_raid_clear_failed_devices(const struct logical_volume *lv); -+int lv_raid_count_failed_devices(const struct logical_volume *lv, uint32_t *failed_cnt); - int lv_writecache_message(const struct logical_volume *lv, const char *msg); - int lv_cache_status(const struct logical_volume *cache_lv, - struct lv_status_cache **status); -diff --git a/lib/metadata/raid_manip.c b/lib/metadata/raid_manip.c -index eb4a2eb45..2a78a0bec 100644 ---- a/lib/metadata/raid_manip.c -+++ b/lib/metadata/raid_manip.c -@@ -3242,7 +3242,7 @@ static int _raid_leg_degraded(struct lv_segment *raid_seg, uint32_t s) - _sublv_is_degraded(seg_metalv(raid_seg, s)))); - } - --/* Return failed component SubLV count for @lv. */ -+/* Return failed component SubLV pair count for @lv. */ - static uint32_t _lv_get_nr_failed_components(const struct logical_volume *lv) - { - uint32_t r = 0, s; -@@ -7328,6 +7328,183 @@ int lv_raid_remove_missing(struct logical_volume *lv) - return 1; - } - -+/* -+ * Count number of failed device bits in dm-raid superblock bit arrays -or- clear them out. -+ * -+ * If any failed devices, return != 0 maximum of failed SubLVs and parity_devs so that the -+ * caller will ask to clear and try activation of the RaidLV unless more than parity_devs -+ * component device pairs (rmeta and rimage) are still failed. This'll allow early exit -+ * in the caller preventing MD kernel rejection to activate the RAID array with > parity_devs -+ * failed component device pairs. -+ */ -+static int _count_or_clear_failed_devices_bits(struct logical_volume *meta_lv, -+ bool clear, uint32_t *nr_failed) -+{ -+ char *meta_path = lv_dmpath_dup(meta_lv->vg->cmd->mem, meta_lv); -+ -+ if (!meta_path) { -+ log_error("Failed to build device path for %s.", -+ display_lvname(meta_lv)); -+ return 0; -+ } -+ -+ if (!clear) /* only counting */ -+ return dm_raid_count_failed_devices(meta_path, nr_failed); -+ -+ return dm_raid_clear_failed_devices(meta_path, nr_failed); -+} -+ -+/* Count or clear failed devices bits in RAID superblocks for -+ * recurred transiently failed component SubLV pairs. */ -+static int _raid_count_or_clear_failed_devices(const struct logical_volume *lv, -+ bool clear, uint32_t *failed_devices) -+{ -+ uint32_t nr_failed = 0, nr_failed_tmp = 0, failed_sublvs = 0, s; -+ struct lv_segment *raid_seg = first_seg(lv); -+ struct logical_volume *meta_lv; -+ const char *str; -+ int r = 1, cleared_devs = 0; -+ -+ /* Prevent bogus use. */ -+ if (!seg_is_raid_with_meta(raid_seg)) { -+ log_error("%s is not a RaidLV with metadata.", display_lvname(lv)); -+ return 0; -+ } -+ -+ failed_sublvs = _lv_get_nr_failed_components(lv); -+ -+ if (clear && (failed_sublvs > raid_seg->segtype->parity_devs)) { -+ log_error("Can't clear transiently failed devices on still failed %s.", -+ display_lvname(lv)); -+ return 0; -+ } -+ -+ if (!raid_seg->meta_areas) { -+ log_error(INTERNAL_ERROR "Missing metadata areas on %s!", display_lvname(lv)); -+ return 0; -+ } -+ -+ /* Check if there isn't any meta LV already active */ -+ for (s = 0; s < raid_seg->area_count; s++) { -+ if (_raid_leg_degraded(raid_seg, s)) -+ continue; -+ -+ meta_lv = seg_metalv(raid_seg, s); -+ -+ if (lv_is_active(meta_lv)) { -+ /* DM table is in some unknown condition, aborting... */ -+ log_error("Can't %s failed devices with active %s metadata volume %s.", -+ clear ? "clear" : "count", -+ lvseg_name(raid_seg), display_lvname(meta_lv)); -+ return 0; -+ } -+ } -+ -+ /* Activate all non degraded meta LVs before count or clear */ -+ for (s = 0; s < raid_seg->area_count; s++) { -+ meta_lv = seg_metalv(raid_seg, s); -+ -+ if (_raid_leg_degraded(raid_seg, s)) { -+ log_debug("Skipping activation of failed devices for degraded %s metadata volume %s.", -+ lvseg_name(raid_seg), display_lvname(meta_lv)); -+ continue; -+ } -+ -+ if (!activate_lv(lv->vg->cmd, meta_lv)) { -+ log_error("Failed to activate %s metadata volume %s.", -+ lvseg_name(raid_seg), display_lvname(meta_lv)); -+ r = 0; /* how many can be counted... */ -+ } -+ } -+ -+ /* Wait for meta activation. */ -+ if (!sync_local_dev_names(lv->vg->cmd)) -+ stack; -+ -+ for (s = 0; s < raid_seg->area_count; s++) { -+ meta_lv = seg_metalv(raid_seg, s); -+ -+ if (_raid_leg_degraded(raid_seg, s)) { -+ if (clear) -+ log_debug("Skipping clear of failed devices for degraded %s metadata volume %s.", -+ lvseg_name(raid_seg), display_lvname(meta_lv)); -+ continue; -+ } -+ -+ if (lv_is_active(meta_lv) && -+ !_count_or_clear_failed_devices_bits(meta_lv, clear, -+ &nr_failed_tmp)) { -+ log_error("Failed to %s failed device(s) in superblock of %s metadata volume %s.", -+ clear ? "clear" : "count", -+ lvseg_name(raid_seg), display_lvname(meta_lv)); -+ r = 0; -+ continue; -+ } -+ -+ if (nr_failed_tmp) { -+ log_verbose("%s %u failed device(s) in superblock of %s metadata volume %s.", -+ clear ? "Cleared" : "Counted", nr_failed_tmp, -+ lvseg_name(raid_seg), display_lvname(meta_lv)); -+ cleared_devs++; -+ } -+ -+ if (nr_failed_tmp > nr_failed) -+ nr_failed = nr_failed_tmp; -+ } -+ -+ /* Deactivate meta LVs */ -+ for (s = 0; s < raid_seg->area_count; s++) { -+ if (_raid_leg_degraded(raid_seg, s)) -+ continue; -+ -+ if (!deactivate_lv(lv->vg->cmd, seg_metalv(raid_seg, s))) { -+ stack; -+ r = 0; -+ } -+ } -+ -+ if (clear) { -+ if (!failed_sublvs) -+ str = "fully operational"; -+ else if (failed_sublvs <= raid_seg->segtype->parity_devs) -+ str = "degraded"; -+ else -+ str = "still failed"; -+ -+ log_print_unless_silent("The %s volume %s is %s with %u transiently failed device(s).", -+ lvseg_name(raid_seg), display_lvname(lv), str, -+ nr_failed - failed_sublvs); -+ -+ if (r && cleared_devs && -+ (failed_sublvs <= raid_seg->segtype->parity_devs)) -+ /* TODO: maybe we want to activate RAID volume here ? */ -+ log_print_unless_silent("Volume has been restored after clearing %u superblocks(s). Once online please check its content.", -+ cleared_devs); -+ } -+ -+ if (failed_devices) -+ *failed_devices = max(failed_sublvs, raid_seg->segtype->parity_devs); -+ -+ return r; -+} -+ -+/* Clear failed device bits in RAID superblocks for recurred -+ * transiently failed component SubLV pairs. */ -+int lv_raid_clear_failed_devices(const struct logical_volume *lv) -+{ -+ return _raid_count_or_clear_failed_devices(lv, true, NULL); -+} -+ -+/* Count failed device bits in RAID superblocks for recurred -+ * transiently failed component SubLV pairs. -+ * -+ * On success, @failed_cnt contains the current number. -+ */ -+int lv_raid_count_failed_devices(const struct logical_volume *lv, uint32_t *failed_cnt) -+{ -+ return _raid_count_or_clear_failed_devices(lv, false, failed_cnt); -+} -+ - /* Return 1 if a partial raid LV can be activated redundantly */ - static int _partial_raid_lv_is_redundant(const struct logical_volume *lv) - { --- -2.49.0 - diff --git a/SOURCES/0010-udev-fix-autoactivation-on-top-of-loop-dev-PVs.patch b/SOURCES/0010-udev-fix-autoactivation-on-top-of-loop-dev-PVs.patch new file mode 100644 index 0000000..36aae68 --- /dev/null +++ b/SOURCES/0010-udev-fix-autoactivation-on-top-of-loop-dev-PVs.patch @@ -0,0 +1,54 @@ +From 4659eb9d2a7b58a9b199d7cf2ccaaf32d6605a76 Mon Sep 17 00:00:00 2001 +From: Peter Rajnoha +Date: Wed, 9 Jul 2025 12:48:48 +0200 +Subject: [PATCH 10/47] udev: fix autoactivation on top of loop dev PVs + +We already check loop devices for LVM_LOOP_PV_ACTIVATED="1" in udev +rules to see if have executed pvscan before. If that is the case, we +don't want to execute it again to avoid VG reactivation. + +However, the rules missed the IMPORT{db}="LVM_LOOP_PV_ACTIVATED" rule +to actually get the value already stored in udev db from previous event. +As a result, the pvscan executed on each CHANGE udev event, hence the +VG autoactivation triggered each time as well. + +Fix this by adding the missing IMPORT{db}="LVM_LOOP_PV_ACTIVATED" rule +(just like we already do for MD devices). + +Note: Keep the behavior for ADD events. That is, we still want the +autoactivation to trigger each time, otherwise coldplug will not work +(again, we have the same principle used for MD devices). + +(cherry picked from commit bd26e768efa534ba95f801c411a2a9581992a993) +--- + WHATS_NEW | 4 ++++ + udev/69-dm-lvm.rules.in | 1 + + 2 files changed, 5 insertions(+) + +diff --git a/WHATS_NEW b/WHATS_NEW +index 635651863..e8db60d53 100644 +--- a/WHATS_NEW ++++ b/WHATS_NEW +@@ -1,3 +1,7 @@ ++Version 2.03.34 - ++================== ++ Fix autoactivation on top of loop dev PVs to trigger once for change uevents. ++ + Version 2.03.33 - 27th June 2025 + ================================ + Various spelling, grammar, formatting, test, and build script improvements. +diff --git a/udev/69-dm-lvm.rules.in b/udev/69-dm-lvm.rules.in +index f7a6eef8f..adcf63453 100644 +--- a/udev/69-dm-lvm.rules.in ++++ b/udev/69-dm-lvm.rules.in +@@ -52,6 +52,7 @@ GOTO="lvm_end" + # Loop device: + LABEL="next" + KERNEL!="loop[0-9]*", GOTO="next" ++IMPORT{db}="LVM_LOOP_PV_ACTIVATED" + ACTION=="add", ENV{LVM_LOOP_PV_ACTIVATED}=="1", GOTO="lvm_scan" + ACTION=="change", ENV{LVM_LOOP_PV_ACTIVATED}!="1", TEST=="loop/backing_file", ENV{LVM_LOOP_PV_ACTIVATED}="1", GOTO="lvm_scan" + GOTO="lvm_end" +-- +2.51.0 + diff --git a/SOURCES/0011-lv_manip.c-fix-lvresize-corruption-in-LV-crypt-FS-st.patch b/SOURCES/0011-lv_manip.c-fix-lvresize-corruption-in-LV-crypt-FS-st.patch new file mode 100644 index 0000000..5c1188e --- /dev/null +++ b/SOURCES/0011-lv_manip.c-fix-lvresize-corruption-in-LV-crypt-FS-st.patch @@ -0,0 +1,81 @@ +From 6ca7cd60fd6afcc0f95dfe20d33044a319621b6d Mon Sep 17 00:00:00 2001 +From: Peter Rajnoha +Date: Fri, 18 Jul 2025 15:06:36 +0200 +Subject: [PATCH 11/47] lv_manip.c: fix lvresize corruption in LV->crypt->FS + stack if near crypt min size limit +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +If we have LV->crypt->FS stack, check that the adjustment for the crypt +data offset will left space for the crypt data itself. Fix possible underflow. + +Example: + +❯ lvs -o name,size vg/lvol0 + lv_name lv_size + lvol0 124.00m + +❯ lsblk /dev/vg/lvol0 +NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS +vg-lvol0 252:2 0 124M 0 lvm +└─a 252:4 0 108M 0 crypt + +Before this patch (the incorrect resulting underflowed file system size after adjustment +for crypt data offset, crypt data then severed by the LV resize without proper +crypt resize beforehand): + +❯ lvreduce --yes --resizefs -L -123M vg/lvol0 + Rounding size to boundary between physical extents: 120.00 MiB. + Checking crypt device /dev/dm-4 on LV vg/lvol0. + File system size 18446744073696968704b is adjusted for crypt data offset 16777216b. + File system ext4+crypto_LUKS found on vg/lvol0. + File system size (108.00 MiB) is smaller than the requested size (<16.00 EiB). + File system reduce is not needed, skipping. + crypt device is already reduced to 113246208 bytes. + Size of logical volume vg/lvol0 changed from 124.00 MiB (31 extents) to 4.00 MiB (1 extents). + Logical volume vg/lvol0 successfully resized. + +With this patch applied: + +❯ lvreduce --yes --resizefs -L -123M vg/lvol0 + Rounding size to boundary between physical extents: 120.00 MiB. + Checking crypt device /dev/dm-4 on LV vg/lvol0. + Crypt header requires 16.00 MiB, not enough space left for crypt data. + +(cherry picked from commit 5da3676ff3901fd099dcdd2bd7478fa9ea4f54dc) +--- + WHATS_NEW | 1 + + lib/metadata/lv_manip.c | 5 +++++ + 2 files changed, 6 insertions(+) + +diff --git a/WHATS_NEW b/WHATS_NEW +index e8db60d53..723638042 100644 +--- a/WHATS_NEW ++++ b/WHATS_NEW +@@ -1,5 +1,6 @@ + Version 2.03.34 - + ================== ++ Fix lvresize corruption in LV->crypt->FS stack if near crypt min size limit. + Fix autoactivation on top of loop dev PVs to trigger once for change uevents. + + Version 2.03.33 - 27th June 2025 +diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c +index 193b1f403..577ffd0b3 100644 +--- a/lib/metadata/lv_manip.c ++++ b/lib/metadata/lv_manip.c +@@ -6478,6 +6478,11 @@ static int _fs_reduce(struct cmd_context *cmd, struct logical_volume *lv, + * 2MB for LUKS1 and 16MB for LUKS2.) + */ + if (fsinfo.needs_crypt) { ++ if (fsinfo.crypt_offset_bytes >= fsinfo.new_size_bytes) { ++ log_error("Crypt header requires %s, not enough space left for crypt data.", ++ display_size(cmd, fsinfo.crypt_offset_bytes >> SECTOR_SHIFT)); ++ goto out; ++ } + fsinfo.new_size_bytes -= fsinfo.crypt_offset_bytes; + log_print_unless_silent("File system size %llub is adjusted for crypt data offset %ub.", + (unsigned long long)fsinfo.new_size_bytes, fsinfo.crypt_offset_bytes); +-- +2.51.0 + diff --git a/SOURCES/0011-lvconvert-allow-clearing-superblocks.patch b/SOURCES/0011-lvconvert-allow-clearing-superblocks.patch deleted file mode 100644 index 342eac4..0000000 --- a/SOURCES/0011-lvconvert-allow-clearing-superblocks.patch +++ /dev/null @@ -1,64 +0,0 @@ -From 4fbda3d36dc02bb682dd8579c8a4ebfc692cbfe3 Mon Sep 17 00:00:00 2001 -From: Zdenek Kabelac -Date: Fri, 31 Jan 2025 21:45:57 +0100 -Subject: [PATCH 11/14] lvconvert: allow clearing superblocks - -(cherry picked from commit 0a8f560c759de0f3335213896c2a3383009c7206) ---- - tools/lvconvert.c | 38 ++++++++++++++++++++++++++++++++++++-- - 1 file changed, 36 insertions(+), 2 deletions(-) - -diff --git a/tools/lvconvert.c b/tools/lvconvert.c -index 72ef74cef..270bae7d0 100644 ---- a/tools/lvconvert.c -+++ b/tools/lvconvert.c -@@ -3874,10 +3874,44 @@ static int _lvconvert_repair_pvs_raid(struct cmd_context *cmd, struct logical_vo - { - struct dm_list *failed_pvs; - int do_it; -+ uint32_t failed_cnt = 0; -+ struct lv_segment *raid_seg; - - if (!lv_is_active(lv_lock_holder(lv))) { -- log_error("%s must be active to perform this operation.", display_lvname(lv)); -- return 0; -+ if (!lv_raid_count_failed_devices(lv, &failed_cnt)) -+ return_0; -+ -+ if (!failed_cnt) { -+ log_error("Logical volume %s must be active to perform this operation.", -+ display_lvname(lv)); -+ return 0; -+ } -+ -+ raid_seg = first_seg(lv); -+ -+ if (failed_cnt > raid_seg->segtype->parity_devs) { -+ log_error("Can't clear %u failed superblock(s) in %s volume %s.", -+ failed_cnt, lvseg_name(raid_seg), display_lvname(lv)); -+ log_print_unless_silent("The maximum number of degraded devices allowed is %u.", -+ raid_seg->segtype->parity_devs); -+ return 0; -+ } -+ -+ if (!arg_count(cmd, yes_ARG) && -+ yes_no_prompt("Attempt to clear %u transiently failed %s superblock(s) in %s? [y/n]: ", -+ failed_cnt, lvseg_name(raid_seg), display_lvname(lv)) == 'n') { -+ log_error("Logical volume %s with %u transiently failed %s superblock(s) NOT repaired.", -+ display_lvname(lv), failed_cnt, lvseg_name(raid_seg)); -+ return 0; -+ } -+ -+ log_verbose("Clearing %u transiently failed %s superblock(s) in %s.", -+ failed_cnt, lvseg_name(raid_seg), display_lvname(lv)); -+ -+ if (!lv_raid_clear_failed_devices(lv)) -+ return_0; -+ -+ return 1; - } - - lv_check_transient(lv); /* TODO check this in lib for all commands? */ --- -2.49.0 - diff --git a/SOURCES/0012-device_id-always-log_error-on-device-ids-write-error.patch b/SOURCES/0012-device_id-always-log_error-on-device-ids-write-error.patch new file mode 100644 index 0000000..a6d21d4 --- /dev/null +++ b/SOURCES/0012-device_id-always-log_error-on-device-ids-write-error.patch @@ -0,0 +1,32 @@ +From 6d7837dc2b93a51bfdad7c796d2b8e3f7fe9f938 Mon Sep 17 00:00:00 2001 +From: Peter Rajnoha +Date: Mon, 21 Jul 2025 13:40:30 +0200 +Subject: [PATCH 12/47] device_id: always log_error on device ids write error + +(cherry picked from commit 03e3b27ba094cc6e58113713a0d36a8b3190a2f3) +--- + lib/device/device_id.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/lib/device/device_id.c b/lib/device/device_id.c +index a3f341bfc..76165559f 100644 +--- a/lib/device/device_id.c ++++ b/lib/device/device_id.c +@@ -1730,12 +1730,12 @@ int device_ids_write(struct cmd_context *cmd) + log_sys_debug("unlink", tmppath); + + if (!(fp = fopen(tmppath, "w+"))) { +- log_warn("Cannot open to write %s.", tmppath); ++ log_error("Cannot open to write %s.", tmppath); + goto out; + } + + if ((dir_fd = open(dirpath, O_RDONLY)) < 0) { +- log_sys_debug("open", dirpath); ++ log_sys_error("open", dirpath); + goto out; + } + +-- +2.51.0 + diff --git a/SOURCES/0012-test-check-raid-superblock-clearing.patch b/SOURCES/0012-test-check-raid-superblock-clearing.patch deleted file mode 100644 index 187f5e5..0000000 --- a/SOURCES/0012-test-check-raid-superblock-clearing.patch +++ /dev/null @@ -1,107 +0,0 @@ -From 7ef2e32ab91194abfcacb96eae2577cf19e66123 Mon Sep 17 00:00:00 2001 -From: Zdenek Kabelac -Date: Sun, 2 Feb 2025 19:21:05 +0100 -Subject: [PATCH 12/14] test: check raid superblock clearing - -(cherry picked from commit 0cafb18978d4a720845c2830fcff129ce9b79327) ---- - test/shell/lvconvert-repair-raid5.sh | 62 +++++++++++++++++++++------- - 1 file changed, 47 insertions(+), 15 deletions(-) - -diff --git a/test/shell/lvconvert-repair-raid5.sh b/test/shell/lvconvert-repair-raid5.sh -index a14d90be9..66485c536 100644 ---- a/test/shell/lvconvert-repair-raid5.sh -+++ b/test/shell/lvconvert-repair-raid5.sh -@@ -1,6 +1,6 @@ - #!/usr/bin/env bash - --# Copyright (C) 2024 Red Hat, Inc. All rights reserved. -+# Copyright (C) 2024-2025 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 -@@ -24,17 +24,31 @@ SKIP_WITH_LVMPOLLD=1 - # - aux have_raid 1 8 0 || skip - --aux prepare_vg 4 --get_devs -+aux prepare_vg 6 - --#offset=$(get first_extent_sector "$dev1") - --# It's possible small raid arrays do have problems with reporting in-sync. --# So try bigger size --RAID_SIZE=8 -+lvcreate --type raid5 -i 5 -L8 -n $lv1 $vg -+aux wait_for_sync $vg $lv1 -+ -+lvs -ao+devices $vg -+ -+# fail 2 drives out of 4 -+aux error_dev "$dev2" -+aux error_dev "$dev3" -+ -+lvchange -an $vg -+ -+aux enable_dev "$dev2" -+aux enable_dev "$dev3" -+ -+lvconvert --yes --repair $vg/$lv1 -v -+ -+lvremove -f $vg - --# RAID1 transient failure check --lvcreate --type raid5 -i 3 -L $RAID_SIZE -n $lv1 $vg -+ -+# Raid5 transient failure check -+ -+lvcreate --type raid5 -i 3 -L8 -n $lv1 $vg - aux wait_for_sync $vg $lv1 - - lvs -ao+devices $vg -@@ -43,17 +57,35 @@ lvs -ao+devices $vg - aux error_dev "$dev2" - aux error_dev "$dev3" - -+not lvconvert --yes --repair $vg/$lv1 -+ - # deactivate immediately - lvchange -an $vg - -+# Raid5 cannot activate with only 2 disks -+not lvchange -ay $vg -+ -+# also it cannot be repaired -+not lvconvert --yes --repair $vg/$lv1 -+ -+# restore 1st. failed drive - aux enable_dev "$dev2" -+ -+# Raid5 should be now repairable -+lvconvert --yes --repair $vg/$lv1 -+ -+# Raid5 volume is working now -+lvchange -ay $vg -+ -+# again deactivate -+lvchange -an $vg -+ -+# restore 2nd. missing drive - aux enable_dev "$dev3" - --# ATM we are failing here with this kernel message: --# --# md/raid:mdX: Cannot continue operation (2/4 failed). --# --# Raid5 LV cannot be started any more --should lvchange -ay $vg -+# still repairable -+lvconvert --yes --repair $vg/$lv1 -+ -+lvchange -ay $vg - - vgremove -ff $vg --- -2.49.0 - diff --git a/SOURCES/0013-lvmdevices-return-error-if-writing-device-ids-fail-f.patch b/SOURCES/0013-lvmdevices-return-error-if-writing-device-ids-fail-f.patch new file mode 100644 index 0000000..bad3767 --- /dev/null +++ b/SOURCES/0013-lvmdevices-return-error-if-writing-device-ids-fail-f.patch @@ -0,0 +1,48 @@ +From f697518550298ec4a571b72f0f6395b42e6fc85d Mon Sep 17 00:00:00 2001 +From: Peter Rajnoha +Date: Mon, 21 Jul 2025 13:41:32 +0200 +Subject: [PATCH 13/47] lvmdevices: return error if writing device ids fail for + --delldev + +(cherry picked from commit 1cd2f35655e79d880d28914998b738baa0be5c07) +--- + tools/lvmdevices.c | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +diff --git a/tools/lvmdevices.c b/tools/lvmdevices.c +index fd766e102..d7d3af59b 100644 +--- a/tools/lvmdevices.c ++++ b/tools/lvmdevices.c +@@ -925,7 +925,8 @@ int lvmdevices(struct cmd_context *cmd, int argc, char **argv) + dev_del: + dm_list_del(&du->list); + free_du(du); +- device_ids_write(cmd); ++ if (!device_ids_write(cmd)) ++ goto_bad; + goto out; + } + +@@ -967,7 +968,8 @@ int lvmdevices(struct cmd_context *cmd, int argc, char **argv) + + dm_list_del(&du->list); + free_du(du); +- device_ids_write(cmd); ++ if (!device_ids_write(cmd)) ++ goto_bad; + goto out; + } + +@@ -1008,7 +1010,8 @@ int lvmdevices(struct cmd_context *cmd, int argc, char **argv) + } + + free_du(du); +- device_ids_write(cmd); ++ if (!device_ids_write(cmd)) ++ goto_bad; + goto out; + } + +-- +2.51.0 + diff --git a/SOURCES/0013-man-update-raid-man.patch b/SOURCES/0013-man-update-raid-man.patch deleted file mode 100644 index d7ed1c8..0000000 --- a/SOURCES/0013-man-update-raid-man.patch +++ /dev/null @@ -1,50 +0,0 @@ -From 63312cb3343d6370c89ab0ff4e93aa39aab25fa5 Mon Sep 17 00:00:00 2001 -From: Zdenek Kabelac -Date: Mon, 12 May 2025 15:05:46 +0200 -Subject: [PATCH 13/14] man: update raid man - -Mention repair of transiently lost devices. - -(cherry picked from commit 22364ce9b68b3a2e03819bfd8fdc569df584b7e2) ---- - man/lvmraid.7_main | 17 ++++++++++++++++- - 1 file changed, 16 insertions(+), 1 deletion(-) - -diff --git a/man/lvmraid.7_main b/man/lvmraid.7_main -index 5b429a410..db8009d46 100644 ---- a/man/lvmraid.7_main -+++ b/man/lvmraid.7_main -@@ -434,7 +434,7 @@ found, run: - # lvs -o name,raid_mismatch_count - .EE - .P --Also, if mismatches were found, the -+Also, if mismatches were found, the - .BR lvs (8) - attr field will display the letter - "m" (mismatch) in the 9th position, e.g. -@@ -862,6 +862,21 @@ those PVs can be reconstructed with: - The rebuild option can be repeated with different PVs to replace the data - on multiple PVs. - . -+.SS Reactivating arrays after temporary device loss -+ -+When a RAID array loses a critical number of devices, -+causing it to lose its ability to function reliably, -+the array will stop and require repair. -+ -+Initiate repair process with this command: -+.P -+.B lvconvert --repair -+.I LV -+.P -+If the previously unavailable devices become accessible again, -+this repair process will update their metadata and -+the RAID array can be reactivated. -+. - .SH DATA INTEGRITY - . - The device mapper integrity target can be used in combination with RAID --- -2.49.0 - diff --git a/SOURCES/0014-WHATS_NEW-update.patch b/SOURCES/0014-WHATS_NEW-update.patch index fd54063..48adbf0 100644 --- a/SOURCES/0014-WHATS_NEW-update.patch +++ b/SOURCES/0014-WHATS_NEW-update.patch @@ -1,25 +1,24 @@ -From 14f920c81c9499bcfcc0414c494f7abc0b9f3d58 Mon Sep 17 00:00:00 2001 -From: Zdenek Kabelac -Date: Mon, 12 May 2025 15:07:15 +0200 -Subject: [PATCH 14/14] WHATS_NEW: update +From 7f6e08eb6d9dfdf82c50151b832c3f5663ea5b9b Mon Sep 17 00:00:00 2001 +From: Peter Rajnoha +Date: Tue, 22 Jul 2025 09:46:39 +0200 +Subject: [PATCH 14/47] WHATS_NEW: update -(cherry picked from commit 759d1bfe113ca7a80248821808d13ed9e011201c) +(cherry picked from commit 986ff7b9cdd6a4af1d79706c80e9660c4ccbf423) --- - WHATS_NEW | 4 ++++ - 1 file changed, 4 insertions(+) + WHATS_NEW | 1 + + 1 file changed, 1 insertion(+) diff --git a/WHATS_NEW b/WHATS_NEW -index 4d8b59681..c9af7be6e 100644 +index 723638042..41fea1a7a 100644 --- a/WHATS_NEW +++ b/WHATS_NEW -@@ -1,3 +1,7 @@ -+Version 2.03.33 - -+================== -+ Repair raid arrays with transiently lost devices. -+ - Version 2.03.32 - 05th May 2025 - =============================== - Lvconvert vdopool conversion propperly validates acceptable LVs. +@@ -1,5 +1,6 @@ + Version 2.03.34 - + ================== ++ Fix lvmdevices --deldev/--delpvid to error out if devices file not writeable. + Fix lvresize corruption in LV->crypt->FS stack if near crypt min size limit. + Fix autoactivation on top of loop dev PVs to trigger once for change uevents. + -- -2.49.0 +2.51.0 diff --git a/SOURCES/0015-device_id-log_warn-instead-of-log_error-in-device_id.patch b/SOURCES/0015-device_id-log_warn-instead-of-log_error-in-device_id.patch new file mode 100644 index 0000000..06e3478 --- /dev/null +++ b/SOURCES/0015-device_id-log_warn-instead-of-log_error-in-device_id.patch @@ -0,0 +1,103 @@ +From cc809a01ac3059fa613473ce45bc75426ab000ad Mon Sep 17 00:00:00 2001 +From: Peter Rajnoha +Date: Wed, 23 Jul 2025 09:17:36 +0200 +Subject: [PATCH 15/47] device_id: log_warn instead of log_error in + device_ids_write + +It is not always the case that the whole command fails if +device_ids_write fail so change all log_error to log_warn and let the +caller decide. + +(cherry picked from commit 80144223e700703f76267b8d033e2d7d04156ee9) +--- + lib/device/device_id.c | 20 ++++++++++---------- + 1 file changed, 10 insertions(+), 10 deletions(-) + +diff --git a/lib/device/device_id.c b/lib/device/device_id.c +index 76165559f..4bb92cb09 100644 +--- a/lib/device/device_id.c ++++ b/lib/device/device_id.c +@@ -1730,12 +1730,12 @@ int device_ids_write(struct cmd_context *cmd) + log_sys_debug("unlink", tmppath); + + if (!(fp = fopen(tmppath, "w+"))) { +- log_error("Cannot open to write %s.", tmppath); ++ log_warn("WARNING: %s: cannot open for writing: %s.", tmppath, strerror(errno)); + goto out; + } + + if ((dir_fd = open(dirpath, O_RDONLY)) < 0) { +- log_sys_error("open", dirpath); ++ log_warn("WARNING: %s: cannot open directory: %s.", dirpath, strerror(errno)); + goto out; + } + +@@ -1748,7 +1748,7 @@ int device_ids_write(struct cmd_context *cmd) + fb_size = names_len + 256 + (128 * dm_list_size(&cmd->use_devices)); + + if (!(fb = malloc(fb_size))) { +- log_error("Failed to allocate buffer size %d for devices file.", fb_size); ++ log_warn("Failed to allocate buffer size %d for devices file.", fb_size); + goto out; + } + +@@ -1762,7 +1762,7 @@ int device_ids_write(struct cmd_context *cmd) + num = snprintf(fb + pos, len - pos, "HOSTNAME=%s\n", cmd->hostname); + + if (num >= len - pos) { +- log_error("Failed to write buffer for devices file content."); ++ log_warn("Failed to write buffer for devices file content."); + goto out; + } + pos += num; +@@ -1772,7 +1772,7 @@ int device_ids_write(struct cmd_context *cmd) + + num = snprintf(fb + pos, len - pos, "%s\n", version_buf); + if (num >= len - pos) { +- log_error("Failed to write buffer for devices file content."); ++ log_warn("Failed to write buffer for devices file content."); + goto out; + } + pos += num; +@@ -1801,7 +1801,7 @@ int device_ids_write(struct cmd_context *cmd) + du->idname ?: ".", devname, pvid); + } + if (num >= len - pos) { +- log_error("Failed to write buffer for devices file content."); ++ log_warn("Failed to write buffer for devices file content."); + goto out; + } + pos += num; +@@ -1820,17 +1820,17 @@ int device_ids_write(struct cmd_context *cmd) + "# HASH=%u\n", + cmd->name, cmd->device_ids_auto_import ? " (auto)" : "", + getpid(), ctime(&t), hash)) < 0) { +- log_error("Failed to write buffer for devices file content."); ++ log_warn("Failed to write buffer for devices file content."); + goto out; + } + fc[fc_bytes] = '\0'; + + if (fputs(fc, fp) < 0) { +- log_error("Failed to write devices file header."); ++ log_warn("Failed to write devices file header."); + goto out; + } + if (fputs(fb, fp) < 0) { +- log_error("Failed to write devices file."); ++ log_warn("Failed to write devices file."); + goto out; + } + if (fflush(fp) < 0) +@@ -1845,7 +1845,7 @@ int device_ids_write(struct cmd_context *cmd) + fp = NULL; + + if (rename(tmppath, cmd->devices_file_path) < 0) { +- log_error("Failed to replace devices file."); ++ log_warn("WARNING: %s: failed to replace devices file: %s", cmd->devices_file_path, strerror(errno)); + goto out; + } + +-- +2.51.0 + diff --git a/SOURCES/0016-lvmdevices-log_error-when-writing-devices-file-fails.patch b/SOURCES/0016-lvmdevices-log_error-when-writing-devices-file-fails.patch new file mode 100644 index 0000000..31e332b --- /dev/null +++ b/SOURCES/0016-lvmdevices-log_error-when-writing-devices-file-fails.patch @@ -0,0 +1,97 @@ +From e845c1a99d660295735d6fd0dd5a048f3980fce7 Mon Sep 17 00:00:00 2001 +From: Peter Rajnoha +Date: Wed, 23 Jul 2025 09:24:07 +0200 +Subject: [PATCH 16/47] lvmdevices: log_error when writing devices file fails + +(cherry picked from commit d5abc55fcf31dbd8b52036340e085c9f7e8d61b2) +--- + tools/lvmdevices.c | 25 +++++++++++++++++++------ + 1 file changed, 19 insertions(+), 6 deletions(-) + +diff --git a/tools/lvmdevices.c b/tools/lvmdevices.c +index d7d3af59b..7f10038d4 100644 +--- a/tools/lvmdevices.c ++++ b/tools/lvmdevices.c +@@ -560,6 +560,7 @@ restart4: + + int lvmdevices(struct cmd_context *cmd, int argc, char **argv) + { ++ static const char failed_to_write_devices_file_msg[] = "Failed to write devices file."; + struct dm_list search_pvids; + struct dm_list found_devs; + struct dm_list scan_devs; +@@ -752,8 +753,10 @@ int lvmdevices(struct cmd_context *cmd, int argc, char **argv) + + if (arg_is_set(cmd, update_ARG)) { + if (update_needed || !dm_list_empty(&found_devs) || cmd->devices_file_hash_mismatch) { +- if (!device_ids_write(cmd)) ++ if (!device_ids_write(cmd)) { ++ log_error(failed_to_write_devices_file_msg); + goto_bad; ++ } + log_print("Updated devices file to version %s", devices_file_version()); + } else { + log_print("No update for devices file is needed."); +@@ -835,8 +838,10 @@ int lvmdevices(struct cmd_context *cmd, int argc, char **argv) + + if (!device_id_add(cmd, dev, dev->pvid, deviceidtype, NULL, 1)) + goto_bad; +- if (!device_ids_write(cmd)) ++ if (!device_ids_write(cmd)) { ++ log_error(failed_to_write_devices_file_msg); + goto_bad; ++ } + goto out; + } + +@@ -884,8 +889,10 @@ int lvmdevices(struct cmd_context *cmd, int argc, char **argv) + if (!device_id_add(cmd, devl->dev, devl->dev->pvid, deviceidtype, NULL, 1)) + goto_bad; + } +- if (!device_ids_write(cmd)) ++ if (!device_ids_write(cmd)) { ++ log_error(failed_to_write_devices_file_msg); + goto_bad; ++ } + goto out; + } + +@@ -925,8 +932,10 @@ int lvmdevices(struct cmd_context *cmd, int argc, char **argv) + dev_del: + dm_list_del(&du->list); + free_du(du); +- if (!device_ids_write(cmd)) ++ if (!device_ids_write(cmd)) { ++ log_error(failed_to_write_devices_file_msg); + goto_bad; ++ } + goto out; + } + +@@ -968,8 +977,10 @@ int lvmdevices(struct cmd_context *cmd, int argc, char **argv) + + dm_list_del(&du->list); + free_du(du); +- if (!device_ids_write(cmd)) ++ if (!device_ids_write(cmd)) { ++ log_error(failed_to_write_devices_file_msg); + goto_bad; ++ } + goto out; + } + +@@ -1010,8 +1021,10 @@ int lvmdevices(struct cmd_context *cmd, int argc, char **argv) + } + + free_du(du); +- if (!device_ids_write(cmd)) ++ if (!device_ids_write(cmd)) { ++ log_error(failed_to_write_devices_file_msg); + goto_bad; ++ } + goto out; + } + +-- +2.51.0 + diff --git a/SOURCES/0017-lvmlockd-lockopt-was-mistakenly-ignored-when-nolocki.patch b/SOURCES/0017-lvmlockd-lockopt-was-mistakenly-ignored-when-nolocki.patch new file mode 100644 index 0000000..728f934 --- /dev/null +++ b/SOURCES/0017-lvmlockd-lockopt-was-mistakenly-ignored-when-nolocki.patch @@ -0,0 +1,56 @@ +From 5653b3e38962d81264dd45db1aad356f6f59dd6c Mon Sep 17 00:00:00 2001 +From: David Teigland +Date: Fri, 8 Aug 2025 14:06:24 -0500 +Subject: [PATCH 17/47] lvmlockd: --lockopt was mistakenly ignored when + --nolocking was set + +(cherry picked from commit 3dc5c3fc9e1dcbca8f74fa5e7df3e0750d66975a) +--- + tools/lvmcmdline.c | 24 +++++++++++++----------- + 1 file changed, 13 insertions(+), 11 deletions(-) + +diff --git a/tools/lvmcmdline.c b/tools/lvmcmdline.c +index 22ae1e3bb..ebb1b87c9 100644 +--- a/tools/lvmcmdline.c ++++ b/tools/lvmcmdline.c +@@ -2969,6 +2969,19 @@ static int _init_lvmlockd(struct cmd_context *cmd) + if (use_lvmlockd) + cmd->enable_hints = 0; + ++ if (arg_is_set(cmd, lockopt_ARG)) { ++ lockd_lockopt_get_flags(arg_str_value(cmd, lockopt_ARG, ""), &cmd->lockopt); ++ ++ if (use_lvmlockd) { ++ if (cmd->lockopt & LOCKOPT_SKIPLV) ++ cmd->lockd_lv_disable = 1; ++ if (cmd->lockopt & LOCKOPT_SKIPVG) ++ cmd->lockd_vg_disable = 1; ++ if (cmd->lockopt & LOCKOPT_SKIPGL) ++ cmd->lockd_gl_disable = 1; ++ } ++ } ++ + if (use_lvmlockd && arg_is_set(cmd, nolocking_ARG)) { + /* --nolocking is only allowed with vgs/lvs/pvs commands */ + cmd->lockd_gl_disable = 1; +@@ -2977,17 +2990,6 @@ static int _init_lvmlockd(struct cmd_context *cmd) + return 1; + } + +- if (use_lvmlockd && arg_is_set(cmd, lockopt_ARG)) { +- lockd_lockopt_get_flags(arg_str_value(cmd, lockopt_ARG, ""), &cmd->lockopt); +- +- if (cmd->lockopt & LOCKOPT_SKIPLV) +- cmd->lockd_lv_disable = 1; +- if (cmd->lockopt & LOCKOPT_SKIPVG) +- cmd->lockd_vg_disable = 1; +- if (cmd->lockopt & LOCKOPT_SKIPGL) +- cmd->lockd_gl_disable = 1; +- } +- + lvmlockd_disconnect(); /* start over when tool context is refreshed */ + lvmlockd_socket = getenv("LVM_LVMLOCKD_SOCKET"); + if (!lvmlockd_socket) +-- +2.51.0 + diff --git a/SOURCES/0018-sanlock-match-lm_lock_sanlock-prototype.patch b/SOURCES/0018-sanlock-match-lm_lock_sanlock-prototype.patch new file mode 100644 index 0000000..bccc318 --- /dev/null +++ b/SOURCES/0018-sanlock-match-lm_lock_sanlock-prototype.patch @@ -0,0 +1,26 @@ +From a70dd84cfdd897a8b9d8cdddd98caaacaa1dff72 Mon Sep 17 00:00:00 2001 +From: Zdenek Kabelac +Date: Wed, 2 Jul 2025 11:46:20 +0200 +Subject: [PATCH 18/47] sanlock: match lm_lock_sanlock prototype + +(cherry picked from commit 95c77bc922ec9867764ddd95df635444804c12ba) +--- + daemons/lvmlockd/lvmlockd-internal.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/daemons/lvmlockd/lvmlockd-internal.h b/daemons/lvmlockd/lvmlockd-internal.h +index 7999c2a03..df69824b6 100644 +--- a/daemons/lvmlockd/lvmlockd-internal.h ++++ b/daemons/lvmlockd/lvmlockd-internal.h +@@ -634,7 +634,7 @@ static inline int lm_add_resource_sanlock(struct lockspace *ls, struct resource + + static inline int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode, + struct val_blk *vb_out, int *retry, struct owner *owner, +- int adopt_only, int adopt_ok) ++ int adopt_only, int adopt_ok, int repair) + { + return -1; + } +-- +2.51.0 + diff --git a/SOURCES/0019-lvmlockd-sanlock-fix-struct-pointer-in-release_renam.patch b/SOURCES/0019-lvmlockd-sanlock-fix-struct-pointer-in-release_renam.patch new file mode 100644 index 0000000..1a777f6 --- /dev/null +++ b/SOURCES/0019-lvmlockd-sanlock-fix-struct-pointer-in-release_renam.patch @@ -0,0 +1,28 @@ +From de5bc8c70577b3d7483c43ce373d233d9089a990 Mon Sep 17 00:00:00 2001 +From: David Teigland +Date: Tue, 1 Jul 2025 10:22:50 -0500 +Subject: [PATCH 19/47] lvmlockd-sanlock: fix struct pointer in release_rename + +(cherry picked from commit 03a343dc9e49b164fe0d153b0b0dc815f18edd6e) +--- + daemons/lvmlockd/lvmlockd-sanlock.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/daemons/lvmlockd/lvmlockd-sanlock.c b/daemons/lvmlockd/lvmlockd-sanlock.c +index ce5953faf..80def0449 100644 +--- a/daemons/lvmlockd/lvmlockd-sanlock.c ++++ b/daemons/lvmlockd/lvmlockd-sanlock.c +@@ -2424,8 +2424,8 @@ static int release_rename(struct lockspace *ls, struct resource *r) + memcpy(&rd1, &rds->rs, sizeof(struct rd_sanlock)); + memcpy(&rd2, &rds->rs, sizeof(struct rd_sanlock)); + +- res1 = (struct sanlk_resource *)&rd1; +- res2 = (struct sanlk_resource *)&rd2; ++ res1 = &rd1.rs; ++ res2 = &rd2.rs; + + if (memcmp(res1->name, r->name, SANLK_NAME_LEN)) + log_error("%s:%s unlock_san release rename bad name %.48s", ls->name, r->name, res1->name); +-- +2.51.0 + diff --git a/SOURCES/0020-lvmlockd-free-structs-in-adopt-error-path.patch b/SOURCES/0020-lvmlockd-free-structs-in-adopt-error-path.patch new file mode 100644 index 0000000..7779e8e --- /dev/null +++ b/SOURCES/0020-lvmlockd-free-structs-in-adopt-error-path.patch @@ -0,0 +1,33 @@ +From 20b81f31c29f416a9c397e41d6998b10fc379228 Mon Sep 17 00:00:00 2001 +From: David Teigland +Date: Tue, 1 Jul 2025 10:53:33 -0500 +Subject: [PATCH 20/47] lvmlockd: free structs in adopt error path + +(cherry picked from commit fcca60fda61b5a545c936e61380e047deb887779) +--- + daemons/lvmlockd/lvmlockd-core.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/daemons/lvmlockd/lvmlockd-core.c b/daemons/lvmlockd/lvmlockd-core.c +index 0cb10369a..369755ac7 100644 +--- a/daemons/lvmlockd/lvmlockd-core.c ++++ b/daemons/lvmlockd/lvmlockd-core.c +@@ -6331,6 +6331,15 @@ static void adopt_locks(void) + return; + + fail: ++ list_for_each_entry_safe(ls, lsafe, &vg_lockd, list) { ++ list_for_each_entry_safe(r, rsafe, &ls->resources, list) { ++ list_del(&r->list); ++ free_resource(r); ++ } ++ list_del(&ls->list); ++ free(ls); ++ } ++ + (void) unlink(adopt_file); + log_error("adopt_locks failed, reset host"); + } +-- +2.51.0 + diff --git a/SOURCES/0021-lvmlockd-sanlock-check-lock_lv_offset_from_args-resu.patch b/SOURCES/0021-lvmlockd-sanlock-check-lock_lv_offset_from_args-resu.patch new file mode 100644 index 0000000..ebbf89b --- /dev/null +++ b/SOURCES/0021-lvmlockd-sanlock-check-lock_lv_offset_from_args-resu.patch @@ -0,0 +1,27 @@ +From d4406030d3fcaa9286fa9ef86fe4ebed04303bbf Mon Sep 17 00:00:00 2001 +From: David Teigland +Date: Tue, 1 Jul 2025 11:23:16 -0500 +Subject: [PATCH 21/47] lvmlockd-sanlock: check lock_lv_offset_from_args result + +(cherry picked from commit f35f074afdaa52b0db098911d97202b478a33085) +--- + daemons/lvmlockd/lvmlockd-sanlock.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/daemons/lvmlockd/lvmlockd-sanlock.c b/daemons/lvmlockd/lvmlockd-sanlock.c +index 80def0449..89df4ec44 100644 +--- a/daemons/lvmlockd/lvmlockd-sanlock.c ++++ b/daemons/lvmlockd/lvmlockd-sanlock.c +@@ -1212,8 +1212,7 @@ int lm_free_lv_sanlock(struct lockspace *ls, struct resource *r) + + strcpy_name_len(rs->name, "#unused", SANLK_NAME_LEN); + +- if (!offset) { +- lock_lv_offset_from_args(r->lv_args, &offset); ++ if (!offset && !lock_lv_offset_from_args(r->lv_args, &offset)) { + rds->rs.disks[0].offset = offset; + log_debug("%s:%s free_lv_san lock_args offset %llu", ls->name, r->name, (unsigned long long)offset); + } +-- +2.51.0 + diff --git a/SOURCES/0022-lvmlockd-always-free-ls-struct-after-ls-thread-exits.patch b/SOURCES/0022-lvmlockd-always-free-ls-struct-after-ls-thread-exits.patch new file mode 100644 index 0000000..04fb2b2 --- /dev/null +++ b/SOURCES/0022-lvmlockd-always-free-ls-struct-after-ls-thread-exits.patch @@ -0,0 +1,57 @@ +From 2477a95fe1a47ff4e8c4c8afda7c4b95dddfaeda Mon Sep 17 00:00:00 2001 +From: David Teigland +Date: Fri, 5 Sep 2025 12:21:12 -0500 +Subject: [PATCH 22/47] lvmlockd: always free ls struct after ls thread exits + +The ls struct was being freed after ls thread exit for common stop, +but was missing when the ls thread was stopped for drop and rename. +Also free ls->actions structs in case any still exist. + +(cherry picked from commit 5b410e589c75d0d540e4ebe4f44cc71b5624cbc6) +--- + daemons/lvmlockd/lvmlockd-core.c | 20 +++++++++----------- + 1 file changed, 9 insertions(+), 11 deletions(-) + +diff --git a/daemons/lvmlockd/lvmlockd-core.c b/daemons/lvmlockd/lvmlockd-core.c +index 369755ac7..f7340ff3e 100644 +--- a/daemons/lvmlockd/lvmlockd-core.c ++++ b/daemons/lvmlockd/lvmlockd-core.c +@@ -3553,6 +3553,7 @@ static int count_lockspace_starting(uint32_t client_id) + static int for_each_lockspace(int do_stop, int do_free, int do_force) + { + struct lockspace *ls, *safe; ++ struct action *act, *act2; + int need_stop = 0; + int need_free = 0; + int stop_count = 0; +@@ -3605,19 +3606,16 @@ static int for_each_lockspace(int do_stop, int do_free, int do_force) + if ((perrno = pthread_join(ls->thread, NULL))) + log_error("pthread_join error %d", perrno); + ++ log_debug("free ls struct %s", ls->name); + list_del(&ls->list); +- +- /* FIXME: will free_vg ever not be set? */ +- +- log_debug("free ls %s", ls->name); +- +- if (ls->free_vg) { +- /* In future we may need to free ls->actions here */ +- free_ls_resources(ls); +- free_pvs_path(&ls->pvs); +- free(ls); +- free_count++; ++ list_for_each_entry_safe(act, act2, &ls->actions, list) { ++ list_del(&act->list); ++ free_action(act); + } ++ free_ls_resources(ls); ++ free_pvs_path(&ls->pvs); ++ free(ls); ++ free_count++; + } else { + need_free++; + } +-- +2.51.0 + diff --git a/SOURCES/0023-man-lvmlockd-updates.patch b/SOURCES/0023-man-lvmlockd-updates.patch new file mode 100644 index 0000000..50a3d2b --- /dev/null +++ b/SOURCES/0023-man-lvmlockd-updates.patch @@ -0,0 +1,582 @@ +From e193db35a368dcd9ac8c9737d774d3552d4cf877 Mon Sep 17 00:00:00 2001 +From: David Teigland +Date: Tue, 23 Sep 2025 11:09:08 -0500 +Subject: [PATCH 23/47] man lvmlockd: updates + +Major rewrite of the beginning description/setup/introduction. + +(cherry picked from commit f15d948720b4a8b52b7929856ee52e20ab0da798) +--- + man/lvmlockd.8_main | 470 +++++++++++++++++++++----------------------- + 1 file changed, 219 insertions(+), 251 deletions(-) + +diff --git a/man/lvmlockd.8_main b/man/lvmlockd.8_main +index 0c0c88ddd..621224df7 100644 +--- a/man/lvmlockd.8_main ++++ b/man/lvmlockd.8_main +@@ -20,33 +20,44 @@ lvmlockd \(em LVM locking daemon + . + .SH DESCRIPTION + . +-LVM commands use lvmlockd to coordinate access to shared storage. ++ ++A shared Volume Group is a VG placed on shared storage devices, e.g. from a ++SAN, that can be used by all the hosts that can access the devices. A ++shared VG requires the use of lvmlockd, and an external lock manager. ++. ++.P ++Different hosts may activate and use LVs in the same shared VG, and ++different hosts can create, extend, or remove LVs in the VG. Locking, ++through lvmlockd, ensures this is all done safely and consistently. ++LVM commands request locks from lvmlockd, which passes the lock requests ++to an external lock manager. Each shared VG has a ++.B locktype ++attribute, specifying the external lock manager to use for the VG. ++. + .P +-When LVM is used on devices shared by multiple hosts, locks will: ++The lock manager options are: ++.B sanlock ++which places locks on storage space reserved within the VG, and ++.B dlm ++which uses a network locking protocol, and has additional clustering ++requirements. ++. ++.P ++There are three types of locking performed through lvmlockd: + .PD 0 + .IP \[bu] 2 +-coordinate reading and writing of LVM metadata ++per-VG locks protect changes to the VG metadata. + .IP \[bu] +-validate caching of LVM metadata ++LV locks limit LV activation to one host at a time. + .IP \[bu] +-prevent conflicting activation of logical volumes +-.PD +-.P +-lvmlockd uses an external lock manager to perform basic locking. +-.P +-Lock manager (lock type) options are: +-. +-.TP 8 +-.B sanlock +-\(en places locks on disk within LVM storage. +-. +-.TP +-.B dlm +-\(en uses network communication and a cluster manager. ++A Global lock protects unused PVs and the VG namespace. + .PD + . + .SH OPTIONS + . ++lvmlockd daemon command line options: ++.P ++. + .TP + .BR -h | --help + Show this help information. +@@ -108,193 +119,212 @@ Override the default sanlock I/O timeout. + .BR -A | --adopt " " 0 | 1 + Enable (1) or disable (0) lock adoption. + . +-.SH USAGE +-. +-.SS Initial set up ++.SH SETUP + . +-Setting up LVM to use lvmlockd and a shared VG for the first time includes +-some one time set up steps: +-. +-.SS 1. choose a lock manager +-. +-.TP 8 +-.B sanlock +-Choose sanlock if dlm/corosync are not otherwise required. +-sanlock does not depend on any clustering software or configuration. +-. +-.TP +-.B dlm +-If dlm (or corosync) are already being used by other cluster +-software, then select dlm. dlm uses corosync which requires additional +-configuration beyond the scope of this document. See corosync and dlm +-documentation for instructions on configuration, set up and usage. +-. +-.SS 2. configure hosts to use lvmlockd +-. +-On all hosts running lvmlockd, configure +-.BR lvm.conf (5): ++The following steps provide a quick overview of how to use shared VGs. ++More details can be found under SETUP DETAILS. + .P +-.EX +-use_lvmlockd = 1 +-.EE +-. +-.TP 8 +-.B sanlock +-Assign each host a unique host_id in the range 1-2000 by setting ++.I Devices ++.P ++Identify the shared device(s) that will be used in the shared VG, ++and add them to each host's devices file (local device names often ++differ, unless a WWN-based name from /dev/disk/by-id is used.) + .br +-.I #DEFAULT_SYS_DIR#/lvmlocal.conf +-local/host_id +-. +-.SS 3. start lvmlockd +-. +-Start the lvmlockd daemon. ++.B $ lvmdevices --adddev ++.I device ++.P ++.I Configuration ++.P ++Edit lvm.conf, setting ++.B use_lvmlockd=1 ++on each host using a shared VG. ++.P ++Edit lvmlocal.conf, setting ++.B host_id ++on each host (only required when using sanlock.) ++The host_id is a unique integer for each host between 1 and 2000. ++.P ++.I Locking ++.P ++Start lvmlockd and the external lock manager (sanlock or dlm) on ++each host. ++.P ++.I VG ++.P ++Create a shared VG from one host (uses the running lock manager): + .br +-Use systemctl, a cluster resource agent, or run directly, e.g. ++.B $ vgcreate --shared ++.I VG ++.I devices + .P +-.EX +-systemctl start lvmlockd +-.EE +-. +-.SS 4. start lock manager +-. +-.TP 8 +-.B sanlock +-Start the sanlock and wdmd daemons. ++Start the lockspace for the shared VG on all hosts: + .br +-Use systemctl or run directly, e.g. +-.sp +-.EX +-systemctl start wdmd sanlock +-.EE +-. +-.TP +-.B dlm +-Start the dlm and corosync daemons. ++.B $ vgchange --lockstart ++.I VG ++.P ++.I Usage ++.P ++Begin using the VG, e.g. creating LVs. ++.P ++Regular shutdown steps: ++.br ++ $ vgchange -an VG ++.br ++ $ vgchange --lockstop VG ++.br ++ $ stop lvmlockd and lock manager + .br +-Use systemctl, a cluster resource agent, or run directly, e.g. +-.sp +-.EX +-systemctl start corosync dlm +-.EE +-. +-.SS 5. create VG on shared devices +-. +-vgcreate --shared + .P +-The shared option sets the VG lock type to sanlock or dlm depending on +-which lock manager is running. LVM commands acquire locks from lvmlockd, +-and lvmlockd uses the chosen lock manager. +-. +-.SS 6. start VG on all hosts +-. +-.EX +-vgchange --lockstart +-.EE ++Regular startup steps: ++.br ++ $ start lvmlockd and lock manager ++.br ++ $ vgchange --lockstart VG + .P +-Shared VGs must be started before they are used. Starting the VG performs +-lock manager initialization that is necessary to begin using locks (i.e. +-creating and joining a lockspace). Starting the VG may take some time, +-and until the start completes the VG may not be modified or activated. + . +-.SS 7. create and activate LVs +-. +-Standard lvcreate and lvchange commands are used to create and activate +-LVs in a shared VG. ++.SH SETUP DETAILS ++.P ++.B Identifying devices ++.br ++Devices often have different local names on each host, e.g. /dev/sda ++on one host is named /dev/sdb on another. One method to identify the ++same device on each host is to run the command lsblk -o+WWN on each ++host, looking for the same WWN, and its corresponding local device name. ++Or, the WWN-based device symlinks under /dev/disk/by-id/ can be a ++useful way to consistently identify a device across multiple hosts. ++.P ++.B Device access ++.br ++On each host, LVM needs to be given access to the shared devices by ++adding them to the local system.devices file (unless the devices file ++feature has been disabled.) Use the local device name identified ++in the previous step, or a WWN-based device symlink, and run the ++command lvmdevices --adddev device_path to add each of the shared ++devices to the local system.devices file. ++Alternatively, after the shared VG has been created from one host, ++other hosts can run the command vgimportdevices VG to add devices ++from VG to system.devices. ++See ++.BR lvmdevices (8) ++for more information. ++.P ++.B Config files ++.br ++After #DEFAULT_SYS_DIR#/lvm.conf use_lvmlockd has been set to 1, ++lvm commands will begin attempting to acquire locks from lvmlockd. ++Failures to acquire the global lock from lvmlockd may appear until ++the first shared VG is operational. These warnings won't interfere ++with lvm commands doing read operations, but lvm commands attempting ++to write may fail with a global lock error. ++.P ++The #DEFAULT_SYS_DIR#/lvmlocal.conf host_id setting is only required ++when using VGs with lock type sanlock. Each host using sanlock VGs ++must be configured with a unique host_id value. Valid host_ids are ++integers in the range 1-2000. (The lvmlocal.conf descriptions of ++host_id and sanlock_align_size mention special cases with 4K disks ++in which the valid host_id range can be smaller, e.g. 1-250.) ++.P ++.B Lock managers ++.br ++A specific build of LVM may exclude support for sanlock or dlm ++lock managers. To check this, run the command "lvm version" and ++look for "--enable-lvmlockd-sanlock" or "--enable-lvmlockd-dlm". ++.P ++With the --shared option, vgcreate searches for a running lock manager ++(dlm or sanlock), and uses the result for the VG lock type. ++In place of --shared, vgcreate --locktype sanlock|dlm can be specified ++directly. + .P +-An LV activated exclusively on one host cannot be activated on another. +-When multiple hosts need to use the same LV concurrently, the LV can be +-activated with a shared lock (see lvchange options -aey vs -asy.) +-(Shared locks are disallowed for certain LV types that cannot be used from +-multiple hosts.) ++When using lvmlockd in a cluster which already uses corosync and ++dlm, then the dlm lock type should be used for shared VGs. Otherwise, ++using sanlock is usually more straight forward. ++.P ++Details on starting or setting up each lock manager are outside the ++scope of LVM. sanlock can usually be started with a simple ++"systemctl start wdmd sanlock". Steps for setting up and starting ++corosync and dlm can be more complicated. ++.P ++.B Lock start ++.br ++Shared VGs must be started before they are used via vgchange --lockstart ++VG. Starting the VG performs lock manager initialization that is necessary ++to begin using locks (i.e. creating and joining a lockspace). Starting the ++VG may take some time, and until the start completes the VG may not be ++modified or activated. When shutting down, the lockspace is stopped with ++vgchange --lockstop VG. + . +-.SS Normal start up and shut down ++.SH TOPICS + . +-After initial set up, start up and shut down include the following steps. +-They can be performed directly or may be automated using systemd or a +-cluster resource manager/agents. When using lvmlockd.service, daemon +-options can be set in +-.I /etc/sysconfig/lvmlockd +-as OPTIONS='-x1 -y2'. ++.SS Displaying shared VGs ++.P ++The ++.B vgs ++command shows the letter ++.B s ++in the last (sixth) attr position for a shared VG: + . +-.IP \[bu] 2 +-start lvmlockd ++.nf + . +-.IP \[bu] +-start lock manager ++.P ++$ vgs ++ VG #PV #LV #SN Attr VSize VFree ++ vgfoo 1 0 0 wz--ns 992.00m 736.00m ++.fi + . +-.IP \[bu] +-vgchange --lockstart ++.P + . +-.IP \[bu] +-activate LVs in shared VGs ++Or, the shared attribute can be displayed as a ++.B vgs ++reporting field: ++.P ++.nf ++$ vgs -o+shared ++ VG #PV #LV #SN Attr VSize VFree Shared ++ vgfoo 1 0 0 wz--ns 992.00m 736.00m shared ++.fi + .P +-The shut down sequence is the reverse: +-.IP \[bu] 2 +-deactivate LVs in shared VGs +-.IP \[bu] +-vgchange --lockstop +-.IP \[bu] +-stop lock manager +-.IP \[bu] +-stop lvmlockd + . +-.SH TOPICS ++The ++.B vgs ++command can also display the lock type: + . +-.SS Protecting VGs on shared devices ++.P ++.nf ++$ vgs -o+locktype ++ VG #PV #LV #SN Attr VSize VFree LockType ++ vgfoo 1 0 0 wz--ns 992.00m 736.00m sanlock ++.fi ++.P + . +-The following terms are used to describe the different ways of accessing +-VGs on shared devices. ++On hosts that are attached to the shared devices, but do not have ++lvmlockd enabled, the ++.B vgs ++command will not display shared VGs unless the ++.B --shared ++option is added: + . +-.TP +-.I shared VG +-A shared VG exists on shared storage that is visible to multiple hosts. +-LVM acquires locks through lvmlockd to coordinate access to shared VGs. +-A shared VG has lock_type "dlm" or "sanlock", which specifies the lock +-manager lvmlockd will use. +-.sp +-When the lock manager for the lock type is not available (e.g. not started +-or failed), lvmlockd is unable to acquire locks for LVM commands. In this +-situation, LVM commands are only allowed to read and display the VG; +-changes and activation will fail. ++.P ++.nf ++$ vgs --shared ++ VG #PV #LV #SN Attr VSize VFree ++ vgfoo 1 0 0 wz--ns 992.00m 736.00m ++.fi + . +-.TP +-.I local VG +-A local VG is meant to be used by a single host. It has no lock type or +-lock type "none". A local VG typically exists on local (non-shared) +-devices and cannot be used concurrently from different hosts. +-.sp +-If a local VG does exist on shared devices, it should be owned by a single +-host by having the system ID set, see ++.SS System ID ++.br ++In contrast to a shared VG, a local VG can only be used by one host ++at a time, and does not use lvmlockd or a lock manager. If a local VG ++is located on shared devices, then the LVM system ID feature should be ++used to assign one host ownership of the VG. See + .BR lvmsystemid (7). +-The host with a matching system ID can use the local VG and other hosts +-will ignore it. A VG with no lock type and no system ID should be +-excluded from all but one host using +-.BR lvm.conf (5) +-filters. +-Without any of these protections, a local VG on shared devices +-can be easily damaged or destroyed. +-. +-.TP +-.I clvm VG +-A clvm VG (or clustered VG) is a VG on shared storage (like a shared VG) +-that requires clvmd for clustering and locking. See below for converting +-a clvm/clustered VG to a shared VG. +-. +-.SS Shared VGs from hosts not using lvmlockd +-. +-Hosts that do not use shared VGs will not be running lvmlockd. In this +-case, shared VGs that are still visible to the host will be ignored +-(like foreign VGs, see +-.BR lvmsystemid (7)). + .P +-The --shared option for reporting and display commands causes shared VGs +-to be displayed on a host not using lvmlockd, like the --foreign option +-does for foreign VGs. ++For additional protection, the shared devices in a local VG can be ++excluded from the devices file (system.devices) on all hosts except ++for the host that owns the VG. + . + .SS Creating the first sanlock VG + . +-When use_lvmlockd is first enabled in +-.BR lvm.conf (5), ++When use_lvmlockd is first enabled in lvm.conf, + and before the first sanlock VG is created, no global lock will exist. + In this initial state, LVM commands try + and fail to acquire the global lock, producing a warning, +@@ -327,27 +357,12 @@ from concurrent use by another vgcreate on another host. + .P + See below for more information about managing the sanlock global lock. + . +-.SS Using shared VGs ++.SS Removing a shared VG + . +-In the +-.BR vgs (8) +-command, shared VGs are indicated by "s" (for shared) +-in the sixth attr field, +-and by "shared" in the "--options shared" report field. +-The specific lock type and lock args for a shared VG can be +-displayed with: +-.P +-.EX +-# vgs -o+locktype,lockargs +-.EE +-.P +-Shared VGs need to be "started" and "stopped", unlike other types of VGs. +-See the following section for a full description of starting and stopping. +-.P +-Removing a shared VG will fail if other hosts have the VG started. Run +-vgchange --lockstop on all other hosts before vgremove. (It may +-take several seconds before vgremove recognizes that all hosts have +-stopped a sanlock VG.) ++Removing a shared VG will fail if other hosts have the VG started (it must ++be started on the host running vgremove.) Run vgchange --lockstop ++on all other hosts before vgremove. (It may take several seconds before ++vgremove recognizes that all hosts have stopped a sanlock VG.) + . + .SS Starting and stopping VGs + . +@@ -366,32 +381,6 @@ When using the lock type sanlock, starting a VG can take a long time + (potentially minutes if the host was previously shut down without cleanly + stopping the VG.) + .P +-A shared VG can be started after all the following are true: +-.P +-\[bu] +-lvmlockd is running +-.br +-\[bu] +-the lock manager is running +-.br +-\[bu] +-the VG's devices are visible on the system +-.P +-A shared VG can be stopped if all LVs are deactivated. +-.P +-All shared VGs can be started/stopped using: +-.P +-.EX +-# vgchange --lockstart +-# vgchange --lockstop +-.EE +-.P +-Individual VGs can be started/stopped using: +-.br +-vgchange --lockstart \&.\|.\|. +-.br +-vgchange --lockstop \&.\|.\|. +-.P + To make vgchange not wait for start to complete: + .br + vgchange --lockstart --lockopt nowait \&.\|.\|. +@@ -400,21 +389,6 @@ lvmlockd can be asked directly to stop all lockspaces: + .br + lvmlockctl -S|--stop-lockspaces + .P +-To start only selected shared VGs, use the +-.BR lvm.conf (5) +-\fBactivation/lock_start_list\fP. +-When defined, only VG names in this list are +-started by vgchange. If the list is not defined (the default), all +-visible shared VGs are started. To start only "vg1", use the following +-.BR lvm.conf (5) +-configuration: +-.P +-.EX +-activation { +-\ lock_start_list = [ "vg1" ] +-\ \&... +-} +-.EE + . + .SS Internal command locking + . +@@ -664,7 +638,7 @@ dmsetup wipe_table -S "uuid=~LVM && vgname=$VG && lv_layer=\\"\\"" + # check that the error target is in place + dmsetup table -c -S "uuid=~LVM && vgname=$VG && lv_layer=\\"\\"" |grep -vw error + if [[ $? -ne 0 ]] ; then +-\ exit 0 ++exit 0 + fi + exit 1 + .EE +@@ -868,14 +842,11 @@ vgmerge + . + .SS lvmlockd changes from clvmd + . +-(See above for converting an existing clvm VG to a shared VG.) + .P +-While lvmlockd and clvmd are entirely different systems, LVM command usage +-remains similar. Differences are more notable when using lvmlockd's +-sanlock option. +-.P +-Visible usage differences between shared VGs (using lvmlockd) and +-clvm/clustered VGs (using clvmd): ++Prior to the introduction of lvmlockd, clvmd (CLVM) existed with similar ++capabilities, but a very different design. ++Some of the visible usage differences between shared VGs (using lvmlockd) ++and cluster VGs (using clvmd): + . + .IP \[bu] 2 + .BR lvm.conf (5) +@@ -945,9 +916,6 @@ unable to passively check the remote active or lock state of an LV. + . + .nh + .na +-.BR lvm (8), + .BR lvmlockctl (8), +-.BR lvchange (8), +-.BR lvgs (8), +-.BR vgs (8), +-.BR lvm.conf (5) ++.BR sanlock (8), ++.BR dlm_controld (8) +-- +2.51.0 + diff --git a/SOURCES/0024-lvmlockd-allow-1-more-extra-character.patch b/SOURCES/0024-lvmlockd-allow-1-more-extra-character.patch new file mode 100644 index 0000000..9af4e59 --- /dev/null +++ b/SOURCES/0024-lvmlockd-allow-1-more-extra-character.patch @@ -0,0 +1,44 @@ +From 1fee1b03564bb807e7adedefb27180babcd861d0 Mon Sep 17 00:00:00 2001 +From: Zdenek Kabelac +Date: Fri, 27 Jun 2025 11:15:05 +0200 +Subject: [PATCH 24/47] lvmlockd: allow 1 more extra character + +Function dm_strncpy() ensures the last character is \0, +so pass whole array size for buffer size. + +This give 1 extra character for use to store owner state and name. + +(cherry picked from commit 879fb36f0a6c4fda783efbc02b4bf6477f18a4af) +--- + daemons/lvmlockd/lvmlockd-sanlock.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/daemons/lvmlockd/lvmlockd-sanlock.c b/daemons/lvmlockd/lvmlockd-sanlock.c +index 89df4ec44..6ef59b591 100644 +--- a/daemons/lvmlockd/lvmlockd-sanlock.c ++++ b/daemons/lvmlockd/lvmlockd-sanlock.c +@@ -2208,10 +2208,10 @@ int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode, + owner->timestamp = (uint32_t)owner_host.timestamp; + + if ((host_state = _host_flags_to_str(owner_host.flags))) +- dm_strncpy(owner->state, host_state, OWNER_STATE_SIZE-1); ++ dm_strncpy(owner->state, host_state, sizeof(owner->state)); + + if (owner_name) { +- dm_strncpy(owner->name, owner_name, OWNER_NAME_SIZE-1); ++ dm_strncpy(owner->name, owner_name, sizeof(owner->name)); + free(owner_name); + } + +@@ -2553,7 +2553,7 @@ int lm_vg_status_sanlock(struct lockspace *ls, struct action *act) + act->owner.timestamp = (uint32_t)hs->timestamp; + + if ((host_state = _host_flags_to_str(hs->flags))) +- dm_strncpy(act->owner.state, host_state, OWNER_STATE_SIZE-1); ++ dm_strncpy(act->owner.state, host_state, sizeof(act->owner.state)); + + free(hs); + return 0; +-- +2.51.0 + diff --git a/SOURCES/0025-libdm-stats-fix-type-mismatch-in-bit-operations.patch b/SOURCES/0025-libdm-stats-fix-type-mismatch-in-bit-operations.patch new file mode 100644 index 0000000..e12721a --- /dev/null +++ b/SOURCES/0025-libdm-stats-fix-type-mismatch-in-bit-operations.patch @@ -0,0 +1,113 @@ +From 20a049ac3267240de7ffcfb55cf58c08fe7d88a6 Mon Sep 17 00:00:00 2001 +From: Zdenek Kabelac +Date: Fri, 27 Jun 2025 11:38:24 +0200 +Subject: [PATCH 25/47] libdm-stats: fix type mismatch in bit operations + +The stats implementation was using uint64_t for group_id and loop variables +while calling dm_bit_* functions that return int types. This created a +potential issue where large values could be incorrectly handled due to +implicit casting between signed and unsigned types. + +Changes: +- Change loop variables from uint64_t to int in _stats_group_tag_len() +- Change loop variable from uint64_t to int in _stats_clear_group_regions() +- Change loop variables from uint64_t to int in dm_stats_get_counter() +- Change loop variable from uint64_t to int in dm_stats_get_region_len() +- Fix _stats_create_group() to properly handle dm_bit_get_first() return value + +This ensures consistent type usage and prevents potential issues with +values exceeding INT_MAX (2^31 - 1). Also this limitats group_id to 31 bits +as a constraint that may need addressing in the future. + +FIXME: Maybe consider implementing 64-bit variants of dm_bit functions or +documenting this limitation more prominently is this ever become an +issue... + +(cherry picked from commit 2dec6f5493e573b7a4012708931226bcbc9af32f) +--- + libdm/libdm-stats.c | 25 +++++++++++++++---------- + 1 file changed, 15 insertions(+), 10 deletions(-) + +diff --git a/libdm/libdm-stats.c b/libdm/libdm-stats.c +index c1b1cc466..cbcbb6754 100644 +--- a/libdm/libdm-stats.c ++++ b/libdm/libdm-stats.c +@@ -1859,7 +1859,8 @@ bad: + static size_t _stats_group_tag_len(const struct dm_stats *dms, + dm_bitset_t regions) + { +- int64_t i, j, next, nr_regions = 0; ++ int i, j, next; ++ int64_t nr_regions = 0; + size_t buflen = 0, id_len = 0; + + /* check region ids and find last set bit */ +@@ -2124,7 +2125,7 @@ out: + static void _stats_clear_group_regions(struct dm_stats *dms, uint64_t group_id) + { + struct dm_stats_group *group; +- uint64_t i; ++ int i; + + group = &dms->groups[group_id]; + for (i = dm_bit_get_first(group->regions); +@@ -2499,7 +2500,7 @@ void dm_stats_destroy(struct dm_stats *dms) + * i is a variable of type int that holds the current area_id. + */ + #define _foreach_region_area(dms, rid, i) \ +-for ((i) = 0; (i) < _nr_areas_region(&dms->regions[(rid)]); (i)++) \ ++for ((i) = 0; (int)(i) < (int)_nr_areas_region(&dms->regions[(rid)]); (i)++) \ + + /* + * Walk each region that is a member of group_id gid. +@@ -2507,7 +2508,7 @@ for ((i) = 0; (i) < _nr_areas_region(&dms->regions[(rid)]); (i)++) \ + */ + #define _foreach_group_region(dms, gid, i) \ + for ((i) = dm_bit_get_first((dms)->groups[(gid)].regions); \ +- (i) != DM_STATS_GROUP_NOT_PRESENT; \ ++ (int)(i) != (int)DM_STATS_GROUP_NOT_PRESENT; \ + (i) = dm_bit_get_next((dms)->groups[(gid)].regions, (i))) \ + + /* +@@ -2562,8 +2563,8 @@ uint64_t dm_stats_get_counter(const struct dm_stats *dms, + dm_stats_counter_t counter, + uint64_t region_id, uint64_t area_id) + { +- uint64_t i, j, sum = 0; /* aggregation */ +- int sum_regions = 0; ++ uint64_t sum = 0; /* aggregation */ ++ int i, j, sum_regions = 0; + struct dm_stats_region *region; + struct dm_stats_counters *area; + +@@ -3129,7 +3130,7 @@ int dm_stats_get_region_start(const struct dm_stats *dms, uint64_t *start, + int dm_stats_get_region_len(const struct dm_stats *dms, uint64_t *len, + uint64_t region_id) + { +- uint64_t i; ++ int i; + if (!dms || !dms->regions) + return_0; + +@@ -3970,11 +3971,15 @@ static int _stats_create_group(struct dm_stats *dms, dm_bitset_t regions, + const char *alias, uint64_t *group_id) + { + struct dm_stats_group *group; +- *group_id = dm_bit_get_first(regions); ++ int i = dm_bit_get_first(regions); + +- /* group has no regions? */ +- if (*group_id == DM_STATS_GROUP_NOT_PRESENT) ++ if (i < 0) { ++ /* group has no regions? */ ++ *group_id = DM_STATS_GROUP_NOT_PRESENT; + return_0; ++ } ++ ++ *group_id = (uint64_t)i; + + group = &dms->groups[*group_id]; + +-- +2.51.0 + diff --git a/SOURCES/0026-cov-prevent-potential-negative-array-index.patch b/SOURCES/0026-cov-prevent-potential-negative-array-index.patch new file mode 100644 index 0000000..7af8164 --- /dev/null +++ b/SOURCES/0026-cov-prevent-potential-negative-array-index.patch @@ -0,0 +1,41 @@ +From c25e62f4e0532dfb55e2c81a6e236edfeffa8c11 Mon Sep 17 00:00:00 2001 +From: Zdenek Kabelac +Date: Sun, 29 Jun 2025 20:47:13 +0200 +Subject: [PATCH 26/47] cov: prevent potential negative array index + +The _stats_map_extents() function processes file extents returned +by FIEMAP ioctl calls. When handling the case where a file has +only a single extent, the code accesses fm_ext[i - 1] to check +if the logical offset is 0. + +However, when i is 0 (no extents processed yet), this results in a negative +array index access which can cause undefined behavior or crashes. + +So check early whether there are fm_mapped_extents to process. +This avoids using negative index array. + +Existing code already checks fm_mapped_extents == 0 before calling +this function so the patch is not fixing any real bug. + +(cherry picked from commit 2a2ad7317f19f15982045d847aacd74922a28572) +--- + libdm/libdm-stats.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/libdm/libdm-stats.c b/libdm/libdm-stats.c +index cbcbb6754..53c3c5480 100644 +--- a/libdm/libdm-stats.c ++++ b/libdm/libdm-stats.c +@@ -4411,6 +4411,9 @@ static uint64_t _stats_map_extents(int fd, struct dm_pool *mem, + uint64_t expected = 0, nr_extents = next_extent; + unsigned int i; + ++ if (!fiemap->fm_mapped_extents) ++ return 0; ++ + /* + * Loop over the returned extents adding the fm_pending extent + * to the table of extents each time a discontinuity (or eof) +-- +2.51.0 + diff --git a/SOURCES/0027-cov-fix-integer-underflow-in-_count-handling.patch b/SOURCES/0027-cov-fix-integer-underflow-in-_count-handling.patch new file mode 100644 index 0000000..1849e0e --- /dev/null +++ b/SOURCES/0027-cov-fix-integer-underflow-in-_count-handling.patch @@ -0,0 +1,65 @@ +From fa4c75d8e20019a11c722d1cc7f3923b3e4b5324 Mon Sep 17 00:00:00 2001 +From: Zdenek Kabelac +Date: Fri, 27 Jun 2025 13:46:01 +0200 +Subject: [PATCH 27/47] cov: fix integer underflow in _count handling + +The _count variable was declared as uint64_t but used in arithmetic operations +that could result in underflow when subtracting from smaller values. This +could cause issues when calculating interval numbers or handling count-based +reporting. + +Changes: +- Change _count variable type from uint64_t to int64_t +- Update _interval_num() to use proper casting for arithmetic +- Change UINT64_MAX to INT64_MAX for default count value +- Remove unnecessary casting in count assignment + +This prevents potential underflow issues when _count is decremented or used +in subtraction operations, ensuring proper behavior for interval-based +reporting and count tracking in dmsetup commands. + +The fix maintains compatibility while providing safer integer arithmetic +for the reporting loop logic. + +(cherry picked from commit 8873599b66612852136b3dbcb4ebefe0164271dd) +--- + libdm/dm-tools/dmsetup.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/libdm/dm-tools/dmsetup.c b/libdm/dm-tools/dmsetup.c +index bf8449e35..2d6ed0a71 100644 +--- a/libdm/dm-tools/dmsetup.c ++++ b/libdm/dm-tools/dmsetup.c +@@ -268,7 +268,7 @@ static struct dm_tree *_dtree; + static struct dm_report *_report; + static report_type_t _report_type; + static dev_name_t _dev_name_type; +-static uint64_t _count = 1; /* count of repeating reports */ ++static int64_t _count = 1; /* count of repeating reports */ + static struct dm_timestamp *_initial_timestamp = NULL; + static uint64_t _disp_factor = 512; /* display sizes in sectors */ + static char _disp_units = 's'; +@@ -593,7 +593,7 @@ static struct dm_split_name *_get_split_name(const char *uuid, const char *name, + static uint64_t _interval_num(void) + { + uint64_t count_arg = _int_args[COUNT_ARG]; +- return ((uint64_t) _int_args[COUNT_ARG] - _count) + !!count_arg; ++ return (uint64_t)(_int_args[COUNT_ARG] - _count) + !!count_arg; + } + + #ifdef HAVE_SYS_TIMERFD_H +@@ -7342,9 +7342,9 @@ unknown: + } + + if (_switches[COUNT_ARG] && _int_args[COUNT_ARG]) +- _count = (uint64_t)_int_args[COUNT_ARG]; ++ _count = _int_args[COUNT_ARG]; + else if (_switches[COUNT_ARG] || _switches[INTERVAL_ARG]) +- _count = UINT64_MAX; ++ _count = INT64_MAX; + + if (_switches[UNITS_ARG]) { + _disp_factor = _factor_from_units(_string_args[UNITS_ARG], +-- +2.51.0 + diff --git a/SOURCES/0028-cov-fix-va_end-resource-leak-in-szscanf.patch b/SOURCES/0028-cov-fix-va_end-resource-leak-in-szscanf.patch new file mode 100644 index 0000000..234617d --- /dev/null +++ b/SOURCES/0028-cov-fix-va_end-resource-leak-in-szscanf.patch @@ -0,0 +1,39 @@ +From 15164d1c1f84cd583e93b13e277f4cbae310b03b Mon Sep 17 00:00:00 2001 +From: Zdenek Kabelac +Date: Sat, 28 Jun 2025 22:42:17 +0200 +Subject: [PATCH 28/47] cov: fix va_end resource leak in szscanf() + +- Fix potential resource leak by ensuring va_end() is called on error path +- Set matched = -1 and break from while loop instead of immediate return +- This ensures proper cleanup of va_list when unsupported format + specifiers are encountered in lvmlockctl. + +The szscanf function is a custom string scanner used for parsing lvmlockd +status information. Previously, encountering an unsupported format +specifier would cause an immediate return without calling va_end(), +leading to undefined behavior and potential resource leaks. + +This fix ensures proper cleanup of variable argument lists in all code paths. + +(cherry picked from commit a53352b4aaa9277cec96f61c50b05d6334320bfe) +--- + daemons/lvmlockd/lvmlockctl.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/daemons/lvmlockd/lvmlockctl.c b/daemons/lvmlockd/lvmlockctl.c +index 5a4512095..4623e349d 100644 +--- a/daemons/lvmlockd/lvmlockctl.c ++++ b/daemons/lvmlockd/lvmlockctl.c +@@ -181,7 +181,8 @@ static int szscanf(const char *input, const char *format, ...) + + } else { + /* unsupported format specifier */ +- return -1; ++ matched = -1; ++ break; + } + + /* advance past 'd', 'u', or 's' character */ +-- +2.51.0 + diff --git a/SOURCES/0029-cov-add-explicit-check-for-0-size.patch b/SOURCES/0029-cov-add-explicit-check-for-0-size.patch new file mode 100644 index 0000000..57db827 --- /dev/null +++ b/SOURCES/0029-cov-add-explicit-check-for-0-size.patch @@ -0,0 +1,44 @@ +From b2814746de3fac6809c07dbd74ca606388a57aa8 Mon Sep 17 00:00:00 2001 +From: Zdenek Kabelac +Date: Mon, 30 Jun 2025 13:55:11 +0200 +Subject: [PATCH 29/47] cov: add explicit check for 0 size + +(cherry picked from commit ae407d2f3cb1d607463d6d5964e44f11857cdb1f) +--- + device_mapper/libdm-report.c | 4 +++- + libdm/libdm-report.c | 4 +++- + 2 files changed, 6 insertions(+), 2 deletions(-) + +diff --git a/device_mapper/libdm-report.c b/device_mapper/libdm-report.c +index b2dc1b70c..1521708ed 100644 +--- a/device_mapper/libdm-report.c ++++ b/device_mapper/libdm-report.c +@@ -3832,7 +3832,9 @@ static struct field_selection *_create_field_selection(struct dm_report *rh, + goto bad; + fs->value->v.l = *((struct selection_str_list **) custom); + +- s_arr_size = dm_list_size(&fs->value->v.l->str_list.list); ++ if (!(s_arr_size = dm_list_size(&fs->value->v.l->str_list.list))) ++ break; ++ + if (!(s_arr = malloc(sizeof(char *) * s_arr_size))) { + log_error("dm_report: malloc failed for regex array " + "for selection field %s", field_id); +diff --git a/libdm/libdm-report.c b/libdm/libdm-report.c +index 18f7b6eb8..b8686901f 100644 +--- a/libdm/libdm-report.c ++++ b/libdm/libdm-report.c +@@ -3829,7 +3829,9 @@ static struct field_selection *_create_field_selection(struct dm_report *rh, + goto bad; + fs->value->v.l = *((struct selection_str_list **) custom); + +- s_arr_size = dm_list_size(&fs->value->v.l->str_list.list); ++ if (!(s_arr_size = dm_list_size(&fs->value->v.l->str_list.list))) ++ break; ++ + if (!(s_arr = malloc(sizeof(char *) * s_arr_size))) { + log_error("dm_report: malloc failed for regex array " + "for selection field %s", field_id); +-- +2.51.0 + diff --git a/SOURCES/0030-cov-explicitly-zero-allocated-mem-for-array.patch b/SOURCES/0030-cov-explicitly-zero-allocated-mem-for-array.patch new file mode 100644 index 0000000..ed6e83e --- /dev/null +++ b/SOURCES/0030-cov-explicitly-zero-allocated-mem-for-array.patch @@ -0,0 +1,47 @@ +From 51f6e02a458f763d4066782549f0b3873317119d Mon Sep 17 00:00:00 2001 +From: Zdenek Kabelac +Date: Mon, 30 Jun 2025 14:32:10 +0200 +Subject: [PATCH 30/47] cov: explicitly zero allocated mem for array + +Replace malloc() with calloc() when allocating the string pointer array +for regex pattern matching in _create_field_selection(). This ensures +all array elements are initialized to NULL pointers, preventing potential +use of uninitialized memory objected by Coverity. + +Existing code sets all elements in the follow up loop. + +(cherry picked from commit 2c5489dd13045624e9597d11a85a29c8408cc0e8) +--- + device_mapper/libdm-report.c | 2 +- + libdm/libdm-report.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/device_mapper/libdm-report.c b/device_mapper/libdm-report.c +index 1521708ed..4c3f3266a 100644 +--- a/device_mapper/libdm-report.c ++++ b/device_mapper/libdm-report.c +@@ -3835,7 +3835,7 @@ static struct field_selection *_create_field_selection(struct dm_report *rh, + if (!(s_arr_size = dm_list_size(&fs->value->v.l->str_list.list))) + break; + +- if (!(s_arr = malloc(sizeof(char *) * s_arr_size))) { ++ if (!(s_arr = calloc(s_arr_size, sizeof(char *)))) { + log_error("dm_report: malloc failed for regex array " + "for selection field %s", field_id); + goto error; +diff --git a/libdm/libdm-report.c b/libdm/libdm-report.c +index b8686901f..36d99f7d7 100644 +--- a/libdm/libdm-report.c ++++ b/libdm/libdm-report.c +@@ -3832,7 +3832,7 @@ static struct field_selection *_create_field_selection(struct dm_report *rh, + if (!(s_arr_size = dm_list_size(&fs->value->v.l->str_list.list))) + break; + +- if (!(s_arr = malloc(sizeof(char *) * s_arr_size))) { ++ if (!(s_arr = calloc(s_arr_size, sizeof(char *)))) { + log_error("dm_report: malloc failed for regex array " + "for selection field %s", field_id); + goto error; +-- +2.51.0 + diff --git a/SOURCES/0031-cov-check-for-potential-empty-registry-list.patch b/SOURCES/0031-cov-check-for-potential-empty-registry-list.patch new file mode 100644 index 0000000..e5ed7b6 --- /dev/null +++ b/SOURCES/0031-cov-check-for-potential-empty-registry-list.patch @@ -0,0 +1,34 @@ +From 940d475e612a8ae2e3fe48213e7ed2a5c2a40705 Mon Sep 17 00:00:00 2001 +From: Zdenek Kabelac +Date: Mon, 30 Jun 2025 14:11:16 +0200 +Subject: [PATCH 31/47] cov: check for potential empty registry list + +Check early for empty thread_registry list and return EINVAL +instead of doing zero length allocation. + +(cherry picked from commit bf580fcc2f17a0c7c732b929ed08acaf9dd831d7) +--- + daemons/dmeventd/dmeventd.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/daemons/dmeventd/dmeventd.c b/daemons/dmeventd/dmeventd.c +index b823a0476..2224ba23e 100644 +--- a/daemons/dmeventd/dmeventd.c ++++ b/daemons/dmeventd/dmeventd.c +@@ -680,7 +680,12 @@ static int _get_status(struct message_data *message_data) + return -EINVAL; + + _lock_mutex(); +- count = dm_list_size(&_thread_registry); ++ if (!(count = dm_list_size(&_thread_registry))) { ++ _unlock_mutex(); ++ ret = -EINVAL; ++ goto out; ++ } ++ + buffers = alloca(sizeof(char*) * count); + dm_list_iterate_items(thread, &_thread_registry) { + if ((current = dm_asprintf(buffers + i, "0:%d %s %s %u %" PRIu32 ";", +-- +2.51.0 + diff --git a/SOURCES/0032-cov-check-for-potential-empty-row-list.patch b/SOURCES/0032-cov-check-for-potential-empty-row-list.patch new file mode 100644 index 0000000..7c6cde0 --- /dev/null +++ b/SOURCES/0032-cov-check-for-potential-empty-row-list.patch @@ -0,0 +1,54 @@ +From ceb2cbb8a9252222e24d919977b149a5f455c11c Mon Sep 17 00:00:00 2001 +From: Zdenek Kabelac +Date: Mon, 30 Jun 2025 14:14:01 +0200 +Subject: [PATCH 32/47] cov: check for potential empty row list + +Skip potential 0 length allocation and return early for empty list. + +(cherry picked from commit 9fcc66316cd5f4b78b78ab1e0d50fafad362d499) +--- + device_mapper/libdm-report.c | 7 +++++-- + libdm/libdm-report.c | 7 +++++-- + 2 files changed, 10 insertions(+), 4 deletions(-) + +diff --git a/device_mapper/libdm-report.c b/device_mapper/libdm-report.c +index 4c3f3266a..343a7edbc 100644 +--- a/device_mapper/libdm-report.c ++++ b/device_mapper/libdm-report.c +@@ -4668,9 +4668,12 @@ static int _sort_rows(struct dm_report *rh) + struct row *(*rows)[]; + uint32_t count = 0; + struct row *row; ++ size_t cnt_rows; + +- if (!(rows = dm_pool_alloc(rh->mem, sizeof(**rows) * +- dm_list_size(&rh->rows)))) { ++ if (!(cnt_rows = dm_list_size(&rh->rows))) ++ return 1; /* nothing to sort */ ++ ++ if (!(rows = dm_pool_alloc(rh->mem, sizeof(**rows) * cnt_rows))) { + log_error("dm_report: sort array allocation failed"); + return 0; + } +diff --git a/libdm/libdm-report.c b/libdm/libdm-report.c +index 36d99f7d7..87c588c3c 100644 +--- a/libdm/libdm-report.c ++++ b/libdm/libdm-report.c +@@ -4665,9 +4665,12 @@ static int _sort_rows(struct dm_report *rh) + struct row *(*rows)[]; + uint32_t count = 0; + struct row *row; ++ size_t cnt_rows; + +- if (!(rows = dm_pool_alloc(rh->mem, sizeof(**rows) * +- dm_list_size(&rh->rows)))) { ++ if (!(cnt_rows = dm_list_size(&rh->rows))) ++ return 1; /* nothing to sort */ ++ ++ if (!(rows = dm_pool_alloc(rh->mem, sizeof(**rows) * cnt_rows))) { + log_error("dm_report: sort array allocation failed"); + return 0; + } +-- +2.51.0 + diff --git a/SOURCES/0033-gcc-for-C90-don-t-mix-declaration-and-code.patch b/SOURCES/0033-gcc-for-C90-don-t-mix-declaration-and-code.patch new file mode 100644 index 0000000..2438608 --- /dev/null +++ b/SOURCES/0033-gcc-for-C90-don-t-mix-declaration-and-code.patch @@ -0,0 +1,61 @@ +From 659e03ed04eff50f12d56baff949d1e7e7b3168b Mon Sep 17 00:00:00 2001 +From: Zdenek Kabelac +Date: Sun, 29 Jun 2025 16:45:49 +0200 +Subject: [PATCH 33/47] gcc: for C90 don't mix declaration and code + +This commit fixes C90 compatibility issues by ensuring variable declarations +are placed at the beginning of code blocks before any executable statements. + +(cherry picked from commit 0be635934c9cb4ac56e53d95adc7d7800d15e11f) +--- + daemons/lvmlockd/lvmlockctl.c | 9 ++++++--- + tools/reporter.c | 3 ++- + 2 files changed, 8 insertions(+), 4 deletions(-) + +diff --git a/daemons/lvmlockd/lvmlockctl.c b/daemons/lvmlockd/lvmlockctl.c +index 4623e349d..e36293260 100644 +--- a/daemons/lvmlockd/lvmlockctl.c ++++ b/daemons/lvmlockd/lvmlockctl.c +@@ -87,12 +87,15 @@ do { \ + static int szscanf(const char *input, const char *format, ...) + { + va_list args; +- va_start(args, format); +- const char *fm = format; +- const char *in = input; ++ const char *fm; ++ const char *in; + int matched = 0; + int n; + ++ va_start(args, format); ++ fm = format; ++ in = input; ++ + while (*fm != '\0') { + + /* +diff --git a/tools/reporter.c b/tools/reporter.c +index 5cc6a2487..e88b8fa72 100644 +--- a/tools/reporter.c ++++ b/tools/reporter.c +@@ -1498,6 +1498,7 @@ int report_format_init(struct cmd_context *cmd) + struct single_report_args *single_args; + struct dm_report_group *new_report_group; + struct dm_report *tmp_log_rh = NULL; ++ const char * radixchar; + + args.log_only = arg_is_set(cmd, logonly_ARG); + report_command_log = args.log_only || find_config_tree_bool(cmd, log_report_command_log_CFG, NULL); +@@ -1522,7 +1523,7 @@ int report_format_init(struct cmd_context *cmd) + cmd->report_strict_type_mode = 1; + + /* For json_std, the radix character must be '.'. */ +- const char * radixchar = nl_langinfo(RADIXCHAR); ++ radixchar = nl_langinfo(RADIXCHAR); + if (radixchar && strcmp(radixchar, ".")) { + log_debug("Radix character for current locale is '%s', json_std requires '.', " + "overriding LC_NUMERIC locale to 'C'", radixchar); +-- +2.51.0 + diff --git a/SOURCES/0034-sanlock-fix-struct-copy-to-avoid-aliasing-issues.patch b/SOURCES/0034-sanlock-fix-struct-copy-to-avoid-aliasing-issues.patch new file mode 100644 index 0000000..f17d781 --- /dev/null +++ b/SOURCES/0034-sanlock-fix-struct-copy-to-avoid-aliasing-issues.patch @@ -0,0 +1,35 @@ +From 6596b120d33f33286f37ba8b2f486fa01978b82e Mon Sep 17 00:00:00 2001 +From: Zdenek Kabelac +Date: Thu, 10 Jul 2025 15:11:30 +0200 +Subject: [PATCH 34/47] sanlock: fix struct copy to avoid aliasing issues + +Replace direct structure assignment with explicit copying to prevent +potential undefined behavior from structure aliasing. This ensures +proper memory handling when working with sanlock structures. + +This possibly fixes regression introduced with commit: e9640e5178769 +as unintended side effect. + +(cherry picked from commit b86b1da80acfa97ee6cc18e3d3a44809d4083a1b) +--- + daemons/lvmlockd/lvmlockd-sanlock.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/daemons/lvmlockd/lvmlockd-sanlock.c b/daemons/lvmlockd/lvmlockd-sanlock.c +index 6ef59b591..93cb3ab17 100644 +--- a/daemons/lvmlockd/lvmlockd-sanlock.c ++++ b/daemons/lvmlockd/lvmlockd-sanlock.c +@@ -2420,8 +2420,8 @@ static int release_rename(struct lockspace *ls, struct resource *r) + if (!res_args) + return -ENOMEM; + +- memcpy(&rd1, &rds->rs, sizeof(struct rd_sanlock)); +- memcpy(&rd2, &rds->rs, sizeof(struct rd_sanlock)); ++ rd1.rs = rds->rs; ++ rd2.rs = rds->rs; + + res1 = &rd1.rs; + res2 = &rd2.rs; +-- +2.51.0 + diff --git a/SOURCES/0035-sanlock-fix-file-descriptor-leak-in-error-path.patch b/SOURCES/0035-sanlock-fix-file-descriptor-leak-in-error-path.patch new file mode 100644 index 0000000..f8fc25f --- /dev/null +++ b/SOURCES/0035-sanlock-fix-file-descriptor-leak-in-error-path.patch @@ -0,0 +1,33 @@ +From e10a604ae404ff6a87eced54743d5a539a06a030 Mon Sep 17 00:00:00 2001 +From: Zdenek Kabelac +Date: Thu, 10 Jul 2025 15:13:18 +0200 +Subject: [PATCH 35/47] sanlock: fix file descriptor leak in error path + +Add proper cleanup of file descriptor in the error handling path +to prevent resource leaks when sanlock operations fail. + +(cherry picked from commit f82c46e6735ce123da27fb576371e660697b0bb7) +--- + daemons/lvmlockd/lvmlockd-sanlock.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/daemons/lvmlockd/lvmlockd-sanlock.c b/daemons/lvmlockd/lvmlockd-sanlock.c +index 93cb3ab17..17820b91d 100644 +--- a/daemons/lvmlockd/lvmlockd-sanlock.c ++++ b/daemons/lvmlockd/lvmlockd-sanlock.c +@@ -320,8 +320,11 @@ static int read_host_id_file(void) + break; + } + } +- _fclose(file, (char *)daemon_host_id_file); ++ + out: ++ if (file) ++ _fclose(file, (char *)daemon_host_id_file); ++ + log_debug("host_id %d from %s", host_id, daemon_host_id_file); + return host_id; + } +-- +2.51.0 + diff --git a/SOURCES/0036-command-lines-fix-typo-in-configurable-name.patch b/SOURCES/0036-command-lines-fix-typo-in-configurable-name.patch new file mode 100644 index 0000000..1d98b19 --- /dev/null +++ b/SOURCES/0036-command-lines-fix-typo-in-configurable-name.patch @@ -0,0 +1,30 @@ +From bf48c1541291aeda537520b664f59249fc85f95b Mon Sep 17 00:00:00 2001 +From: Zdenek Kabelac +Date: Fri, 11 Jul 2025 14:29:41 +0200 +Subject: [PATCH 36/47] command-lines: fix typo in configurable name + +Fix type in lvm.conf option name used for lvcreate +and replace global/mirror_segfault_default with correct +name global/mirror_segtype_default. + +(cherry picked from commit 0b7b6ccd79929611131549a70bcb339f0c67530e) +--- + tools/command-lines.in | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tools/command-lines.in b/tools/command-lines.in +index d85df7bbd..3d38b1ce7 100644 +--- a/tools/command-lines.in ++++ b/tools/command-lines.in +@@ -973,7 +973,7 @@ OP: PV ... + IO: --stripes 1 + ID: lvcreate_mirror_or_raid1 + DESC: Create a raid1 or mirror LV. +-DESC: Implicit type is defined by lvm.conf global/mirror_segfault_default. ++DESC: Implicit type is defined by lvm.conf global/mirror_segtype_default. + AUTOTYPE: raid1 + AUTOTYPE: mirror + +-- +2.51.0 + diff --git a/SOURCES/0037-tools-simplify-LVM_DID_EXEC-environment-variable.patch b/SOURCES/0037-tools-simplify-LVM_DID_EXEC-environment-variable.patch new file mode 100644 index 0000000..832b1a7 --- /dev/null +++ b/SOURCES/0037-tools-simplify-LVM_DID_EXEC-environment-variable.patch @@ -0,0 +1,30 @@ +From 7f5a4a9de4aab40f2c243f0f657008da839cb75f Mon Sep 17 00:00:00 2001 +From: Zdenek Kabelac +Date: Thu, 10 Jul 2025 21:40:14 +0200 +Subject: [PATCH 37/47] tools: simplify LVM_DID_EXEC environment variable + +Set LVM_DID_EXEC to "1" instead of using the command name string, +avoiding potential issues with unusual command names and improving +consistency in environment variable handling. + +(cherry picked from commit 5d16b1d7348aad816424b2a8e95fd31a59c3e2e2) +--- + tools/lvmcmdline.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tools/lvmcmdline.c b/tools/lvmcmdline.c +index ebb1b87c9..2ecdbd164 100644 +--- a/tools/lvmcmdline.c ++++ b/tools/lvmcmdline.c +@@ -3608,7 +3608,7 @@ int lvm2_main(int argc, char **argv) + if (is_static() && strcmp(base, "lvm.static") && + path_exists(LVM_PATH) && + !getenv("LVM_DID_EXEC")) { +- if (setenv("LVM_DID_EXEC", base, 1)) ++ if (setenv("LVM_DID_EXEC", "1", 1)) + log_sys_error("setenv", "LVM_DID_EXEC"); + if (execvp(LVM_PATH, argv) == -1) + log_sys_error("execvp", LVM_PATH); +-- +2.51.0 + diff --git a/SOURCES/0038-gcc-ensure-pointer-is-properly-initialized.patch b/SOURCES/0038-gcc-ensure-pointer-is-properly-initialized.patch new file mode 100644 index 0000000..b7b6c53 --- /dev/null +++ b/SOURCES/0038-gcc-ensure-pointer-is-properly-initialized.patch @@ -0,0 +1,39 @@ +From 89300351f254ce1fe499f6bae609c16a0b1ef60a Mon Sep 17 00:00:00 2001 +From: Zdenek Kabelac +Date: Wed, 9 Jul 2025 23:26:03 +0200 +Subject: [PATCH 38/47] gcc: ensure pointer is properly initialized + +Fix gcc warning by ensuring pointers are properly defined and +initialized before use in man-generator code to prevent potential +undefined behavior. + +(cherry picked from commit a23ef8e26f5468c37d676da15d0125bff6de7095) +--- + tools/man-generator.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/tools/man-generator.c b/tools/man-generator.c +index bd161796a..7a60d4327 100644 +--- a/tools/man-generator.c ++++ b/tools/man-generator.c +@@ -1219,7 +1219,7 @@ static void _print_cmd_usage_option(const struct command_name *cname, + static int _print_man(char *name, char *des_file, int secondary) + { + const struct command_name *cname; +- const struct command_name_args *cna; ++ const struct command_name_args *cna = NULL; + struct command *cmd, *prev_cmd = NULL; + char *lvmname = name; + int i, sep = 0; +@@ -1363,7 +1363,7 @@ static int _print_man(char *name, char *des_file, int secondary) + if (cname && (i == (COMMAND_COUNT - 1))) { + _print_cmd_usage_option(cname, cmd); + } else { +- if (cna->variants > 1) ++ if (cna && cna->variants > 1) + sep = 1; + } + } +-- +2.51.0 + diff --git a/SOURCES/0039-dmeventd-check-device-exists.patch b/SOURCES/0039-dmeventd-check-device-exists.patch new file mode 100644 index 0000000..d7fa056 --- /dev/null +++ b/SOURCES/0039-dmeventd-check-device-exists.patch @@ -0,0 +1,40 @@ +From 4ed321be7a9dcd3df99f3175f03bc45d65989c98 Mon Sep 17 00:00:00 2001 +From: Zdenek Kabelac +Date: Tue, 22 Jul 2025 20:34:38 +0200 +Subject: [PATCH 39/47] dmeventd: check device exists + +Check first whether the monitored device actually really exists, +before resolving its device name. + +In the case device is not present in DM table, fail _fill_device_data(). + +(cherry picked from commit 175a80157a2116a64f72e912c04b4a45a03c50f6) +--- + daemons/dmeventd/dmeventd.c | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +diff --git a/daemons/dmeventd/dmeventd.c b/daemons/dmeventd/dmeventd.c +index 2224ba23e..93dfb9bc0 100644 +--- a/daemons/dmeventd/dmeventd.c ++++ b/daemons/dmeventd/dmeventd.c +@@ -606,11 +606,14 @@ static int _fill_device_data(struct thread_status *ts) + if (!dm_task_run(dmt)) + goto fail; + +- free(ts->device.name); +- if (!(ts->device.name = strdup(dm_task_get_name(dmt)))) ++ if (!dm_task_get_info(dmt, &dmi)) + goto fail; + +- if (!dm_task_get_info(dmt, &dmi)) ++ if (!dmi.exists) ++ goto fail; ++ ++ free(ts->device.name); ++ if (!(ts->device.name = strdup(dm_task_get_name(dmt)))) + goto fail; + + ts->device.major = dmi.major; +-- +2.51.0 + diff --git a/SOURCES/0040-dmeventd-add-device-existence-check.patch b/SOURCES/0040-dmeventd-add-device-existence-check.patch new file mode 100644 index 0000000..853235e --- /dev/null +++ b/SOURCES/0040-dmeventd-add-device-existence-check.patch @@ -0,0 +1,53 @@ +From a7c707334f3b2d571f8fa80db75e631b11e4b09b Mon Sep 17 00:00:00 2001 +From: Zdenek Kabelac +Date: Tue, 22 Jul 2025 20:35:24 +0200 +Subject: [PATCH 40/47] dmeventd: add device existence check + +Add device existence check after successful wait ioctl to prevent +processing events on removed devices. + +When dm_task_run() succeeds on a WAITEVENT ioctl, the success might +actually indicate that the device was removed rather than a genuine +device event. Without this check, dmeventd would attempt to process +ERROR events on non-existent devices, leading to unnecessary error +commands and log noise. + +This fix adds a _fill_device_data() call immediately after successful +wait completion to verify the device still exists. If the device is +gone, execution jumps to the existing ENXIO error path which properly +handles device disappearance. + +Note: Future kernel versions may return ENXIO directly from the wait +ioctl when devices are removed, making this workaround unnecessary. +Until then, this extra INFO ioctl provides the needed verification. + +(cherry picked from commit fa2ec32c4eaab7f6c7e85dd71fba455a0022dc38) +--- + daemons/dmeventd/dmeventd.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/daemons/dmeventd/dmeventd.c b/daemons/dmeventd/dmeventd.c +index 93dfb9bc0..b696cc77a 100644 +--- a/daemons/dmeventd/dmeventd.c ++++ b/daemons/dmeventd/dmeventd.c +@@ -902,6 +902,9 @@ static int _event_wait(struct thread_status *thread) + } + + if (dm_task_run(thread->wait_task)) { ++ /* Recheck device info whether is still exists */ ++ if (!_fill_device_data(thread)) ++ goto disappeared; /* device is gone... */ + thread->current_events |= DM_EVENT_DEVICE_ERROR; + ret = DM_WAIT_INTR; + /* Update event_nr */ +@@ -910,6 +913,7 @@ static int _event_wait(struct thread_status *thread) + } else { + switch (dm_task_get_errno(thread->wait_task)) { + case ENXIO: ++disappeared: + log_error("%s disappeared, detaching.", + thread->device.name); + ret = DM_WAIT_FATAL; +-- +2.51.0 + diff --git a/SOURCES/0041-dmeventd-_get_status-returns-success-for-non-monitor.patch b/SOURCES/0041-dmeventd-_get_status-returns-success-for-non-monitor.patch new file mode 100644 index 0000000..6cb5cdb --- /dev/null +++ b/SOURCES/0041-dmeventd-_get_status-returns-success-for-non-monitor.patch @@ -0,0 +1,37 @@ +From d825680fd9fae523f166a1ff1a833e5157ccce79 Mon Sep 17 00:00:00 2001 +From: Zdenek Kabelac +Date: Tue, 29 Jul 2025 16:00:39 +0200 +Subject: [PATCH 41/47] dmeventd: _get_status returns success for non + monitoring + +No longer returning EINVAL when the dmeventd is not monitoring +any device (there are no registered devices). + +This makes usable i.e. 'dmeventd -R' for the case, the dmeventd +was not monnitoring anything during this call. + +Previously this actually cause refuse of 'restart' - since +restarting 'dmeventd' has seen failing resutl of a call: +DM_EVENT_CMD_GET_STATUS + +(cherry picked from commit 6a31246bdd50ee8619d58704d83e4e916e0608d8) +--- + daemons/dmeventd/dmeventd.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/daemons/dmeventd/dmeventd.c b/daemons/dmeventd/dmeventd.c +index b696cc77a..22a713b9a 100644 +--- a/daemons/dmeventd/dmeventd.c ++++ b/daemons/dmeventd/dmeventd.c +@@ -685,7 +685,7 @@ static int _get_status(struct message_data *message_data) + _lock_mutex(); + if (!(count = dm_list_size(&_thread_registry))) { + _unlock_mutex(); +- ret = -EINVAL; ++ ret = 0; /* no monitored devices */ + goto out; + } + +-- +2.51.0 + diff --git a/SOURCES/0042-vgsplit-fix-check-for-not-splitting-an-LV-between-tw.patch b/SOURCES/0042-vgsplit-fix-check-for-not-splitting-an-LV-between-tw.patch new file mode 100644 index 0000000..be8c644 --- /dev/null +++ b/SOURCES/0042-vgsplit-fix-check-for-not-splitting-an-LV-between-tw.patch @@ -0,0 +1,58 @@ +From 5af9f7beca2c30815707c412dcbe31a109fd0d62 Mon Sep 17 00:00:00 2001 +From: Peter Rajnoha +Date: Fri, 25 Jul 2025 10:45:07 +0200 +Subject: [PATCH 42/47] vgsplit: fix check for not splitting an LV between two + VGs +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Fix check for not splitting an LV between two VGs in case +where the LVs contains an internal layer. + +For example, integrity layer for RAIDs and splitting a PV that +is not part of the RAID LV at all (sdc here): + +❯ vgcreate vg /dev/sda /dev/sdb /dev/sdc + Volume group "vg" successfully created + +❯ lvcreate -l1 -m1 --type raid1 --raidintegrity y vg /dev/sda /dev/sdb + Logical volume "lvol0" created. + +Before this patch: + +❯ vgsplit vg vg2 /dev/sdc + Logical volume vg/lvol0_rimage_0 (part of lvol0) must be inactive. + +❯ vgchange -an vg + 0 logical volume(s) in volume group "vg" now active + +❯ vgsplit vg vg2 /dev/sdc + Can't split LV lvol0_rimage_0 between two Volume Groups + +With this patch applied: + +❯ vgsplit vg vg2 /dev/sdc + New volume group "vg2" successfully split from "vg" + +(cherry picked from commit 185455659347722a5eab26f1cc9f189076847e45) +--- + tools/vgsplit.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tools/vgsplit.c b/tools/vgsplit.c +index e79195019..aa89835d3 100644 +--- a/tools/vgsplit.c ++++ b/tools/vgsplit.c +@@ -170,7 +170,7 @@ static int _move_lvs(struct volume_group *vg_from, struct volume_group *vg_to) + + } + +- if (vg_with == vg_from) ++ if (!vg_with || vg_with == vg_from) + continue; + + /* Move this LV */ +-- +2.51.0 + diff --git a/SOURCES/0043-vgsplit-fix-check-for-not-splitting-an-LV-between-tw.patch b/SOURCES/0043-vgsplit-fix-check-for-not-splitting-an-LV-between-tw.patch new file mode 100644 index 0000000..b6c11a1 --- /dev/null +++ b/SOURCES/0043-vgsplit-fix-check-for-not-splitting-an-LV-between-tw.patch @@ -0,0 +1,88 @@ +From 147d05c177c39d298f02fc6f786e476308413133 Mon Sep 17 00:00:00 2001 +From: Peter Rajnoha +Date: Tue, 12 Aug 2025 11:32:18 +0200 +Subject: [PATCH 43/47] vgsplit: fix check for not splitting an LV between two + VGs for cachevol +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +When cachevol was used for the cache LV, the check for not splitting an +LV between two VGs was incorrect, not allowing to split the VG in cases +it should have been possible. + +For example, splitting a VG which contains the cache LV with cachevol +only on two devices (sda and sdb here) and leaving third device completely +unused (sdc here) should clearly allow us to split it into a new VG: + +❯ vgcreate vg /dev/sd{a..c} + Physical volume "/dev/sda" successfully created. + Physical volume "/dev/sdb" successfully created. + Physical volume "/dev/sdc" successfully created. + Volume group "vg" successfully created + +❯ lvcreate -l2 -n main vg /dev/sda + Logical volume "main" created. + +❯ lvcreate -l2 -n fast vg /dev/sdb + Logical volume "fast" created. + +❯ lvconvert -y --type cache --cachevol fast vg/main + Logical volume vg/main is now cached. + +❯ lvs -a -o name,devices vg + lv_name devices + [fast_cvol] /dev/sdb(0) + main main_corig(0) + [main_corig] /dev/sda(0) + +❯ lsblk -o name /dev/sd{a..c} +NAME +sda +└─vg-main_corig + └─vg-main +sdb +└─vg-fast_cvol + ├─vg-fast_cvol-cdata + │ └─vg-main + └─vg-fast_cvol-cmeta + └─vg-main +sdc + +Before this patch: + +❯ vgsplit vg vg2 /dev/sdc + Logical volume vg/main must be inactive. + +❯ vgchange -an vg + 0 logical volume(s) in volume group "vg" now active + +❯ vgsplit vg vg2 /dev/sdc + Can't split LV main between two Volume Groups + +With this patch applied: + +❯ vgsplit vg vg2 /dev/sdc + New volume group "vg2" successfully split from "vg" + +(cherry picked from commit 3fe57cc892fc984c30fb14c866a109ef17772ed4) +--- + tools/vgsplit.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/tools/vgsplit.c b/tools/vgsplit.c +index aa89835d3..5d6c0a06c 100644 +--- a/tools/vgsplit.c ++++ b/tools/vgsplit.c +@@ -450,6 +450,8 @@ static int _move_cache(struct volume_group *vg_from, + + if (lv_is_cache_vol(lv)) { + fast = lv; ++ } else if (lv_is_cache_vol(seg->lv)) { ++ fast = seg->lv; + } else { + data = seg_lv(seg, 0); + meta = seg->metadata_lv; +-- +2.51.0 + diff --git a/SOURCES/0044-lvmdevices-do-not-create-system.devices-when-deletin.patch b/SOURCES/0044-lvmdevices-do-not-create-system.devices-when-deletin.patch new file mode 100644 index 0000000..8ceb327 --- /dev/null +++ b/SOURCES/0044-lvmdevices-do-not-create-system.devices-when-deletin.patch @@ -0,0 +1,51 @@ +From c370fe563dd095a09f6e070afb8a5c8e4915ec47 Mon Sep 17 00:00:00 2001 +From: David Teigland +Date: Fri, 8 Aug 2025 12:36:11 -0500 +Subject: [PATCH 44/47] lvmdevices: do not create system.devices when deleting + entries + +When using "lvmdevices --deldev" or "lvmdevices --delpvid" and no +system.devices file exists, the commands should not create the file. + +(cherry picked from commit e61aab70498a887557c133fcba21fcc41345d272) +--- + test/shell/devicesfile-edit.sh | 7 +++++++ + tools/lvmdevices.c | 4 ++++ + 2 files changed, 11 insertions(+) + +diff --git a/test/shell/devicesfile-edit.sh b/test/shell/devicesfile-edit.sh +index 5f8eb90ee..4b8f9c008 100644 +--- a/test/shell/devicesfile-edit.sh ++++ b/test/shell/devicesfile-edit.sh +@@ -249,6 +249,13 @@ lvmdevices --update --delnotfound + not grep PVID=aaa $DF + not grep PVID=bbb $DF + ++# test that deldev does not create devices file when it doesn't exist ++rm -f $DF ++test ! -e $DF ++not lvmdevices --deldev "$LOOP1" ++test ! -e $DF ++not lvmdevices --delpvid "$PVID1" ++test ! -e $DF + + # TODO: add/rem of partitions of same device + +diff --git a/tools/lvmdevices.c b/tools/lvmdevices.c +index 7f10038d4..65399c96c 100644 +--- a/tools/lvmdevices.c ++++ b/tools/lvmdevices.c +@@ -590,6 +590,10 @@ int lvmdevices(struct cmd_context *cmd, int argc, char **argv) + return ECMD_FAILED; + } + if (!devices_file_exists(cmd)) { ++ if (arg_is_set(cmd, deldev_ARG) || arg_is_set(cmd, delpvid_ARG) || arg_is_set(cmd, update_ARG)) { ++ log_error("Devices file does not exist."); ++ return ECMD_FAILED; ++ } + if (!devices_file_touch(cmd)) { + log_error("Failed to create the devices file."); + return ECMD_FAILED; +-- +2.51.0 + diff --git a/SOURCES/0045-tools-pvchange-unlock-devices-file-at-the-end-of-cmd.patch b/SOURCES/0045-tools-pvchange-unlock-devices-file-at-the-end-of-cmd.patch new file mode 100644 index 0000000..aa01c47 --- /dev/null +++ b/SOURCES/0045-tools-pvchange-unlock-devices-file-at-the-end-of-cmd.patch @@ -0,0 +1,51 @@ +From 85a712e95a5c0127d27ca3bbbe7019d54393cc33 Mon Sep 17 00:00:00 2001 +From: Peter Rajnoha +Date: Fri, 29 Aug 2025 13:43:20 +0200 +Subject: [PATCH 45/47] tools: pvchange: unlock devices file at the end of cmd + processing +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Unlock devices file at the end of cmd processing, after all the PVs are +processed, not after the first processed PV. + +Before this patch: + +❯ pvchange -u /dev/sda /dev/sdb + Physical volume "/dev/sda" changed + WARNING: Devices file unlock no fd. + Physical volume "/dev/sdb" changed + 2 physical volumes changed / 0 physical volumes not changed + +With this patch applied: + +❯ pvchange -u /dev/sda /dev/sdb + Physical volume "/dev/sda" changed + Physical volume "/dev/sdb" changed + 2 physical volumes changed / 0 physical volumes not changed + +The lvm_run_command/devices_file_exit/unlock_devices_file will +do the unlock at the very end of cmd processing. + +(cherry picked from commit 16d3195a69fbe15d9fad4a16cceec468ea542e5a) +--- + tools/pvchange.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tools/pvchange.c b/tools/pvchange.c +index 339d990ca..d7376c499 100644 +--- a/tools/pvchange.c ++++ b/tools/pvchange.c +@@ -194,7 +194,7 @@ static int _pvchange_single(struct cmd_context *cmd, struct volume_group *vg, + log_error("Failed to set pvid for devices file."); + if (!device_ids_write(cmd)) + log_warn("Failed to update devices file."); +- unlock_devices_file(cmd); ++ //unlock_devices_file(cmd); + } + + log_print_unless_silent("Physical volume \"%s\" changed", pv_name); +-- +2.51.0 + diff --git a/SOURCES/0046-tools-pvchange-unlock-devices-file-at-the-end-of-cmd.patch b/SOURCES/0046-tools-pvchange-unlock-devices-file-at-the-end-of-cmd.patch new file mode 100644 index 0000000..a6835e7 --- /dev/null +++ b/SOURCES/0046-tools-pvchange-unlock-devices-file-at-the-end-of-cmd.patch @@ -0,0 +1,28 @@ +From dcae883b382f03a58a04d72f6a3bb446e4814ae9 Mon Sep 17 00:00:00 2001 +From: Peter Rajnoha +Date: Fri, 29 Aug 2025 13:50:20 +0200 +Subject: [PATCH 46/47] tools: pvchange: unlock devices file at the end of cmd + processing + +Remove the line, not just comment out. + +(cherry picked from commit d89869f17ec217ee758918047b7edba6c9aa017a) +--- + tools/pvchange.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/tools/pvchange.c b/tools/pvchange.c +index d7376c499..1b43b0154 100644 +--- a/tools/pvchange.c ++++ b/tools/pvchange.c +@@ -194,7 +194,6 @@ static int _pvchange_single(struct cmd_context *cmd, struct volume_group *vg, + log_error("Failed to set pvid for devices file."); + if (!device_ids_write(cmd)) + log_warn("Failed to update devices file."); +- //unlock_devices_file(cmd); + } + + log_print_unless_silent("Physical volume \"%s\" changed", pv_name); +-- +2.51.0 + diff --git a/SOURCES/0047-make-generate.patch b/SOURCES/0047-make-generate.patch new file mode 100644 index 0000000..6aa8bb6 --- /dev/null +++ b/SOURCES/0047-make-generate.patch @@ -0,0 +1,162 @@ +From 3a6c6366c0605fbb7b0001d920da6bd801bff689 Mon Sep 17 00:00:00 2001 +From: Marian Csontos +Date: Mon, 29 Sep 2025 15:44:24 +0200 +Subject: [PATCH 47/47] make: generate + +--- + man/lvchange.8_pregen | 6 +++--- + man/lvconvert.8_pregen | 8 ++++---- + man/lvcreate.8_pregen | 10 +++++----- + man/lvextend.8_pregen | 2 +- + man/lvresize.8_pregen | 2 +- + 5 files changed, 14 insertions(+), 14 deletions(-) + +diff --git a/man/lvchange.8_pregen b/man/lvchange.8_pregen +index f45d8001c..1e87db1b8 100644 +--- a/man/lvchange.8_pregen ++++ b/man/lvchange.8_pregen +@@ -891,7 +891,7 @@ See \fBvgcfgbackup\fP(8) for more information. + Specifies when writes to a cache LV should be considered complete. + \fBwriteback\fP considers a write complete as soon as it is + stored in the cache pool. +-\fBwritethough\fP considers a write complete only when it has ++\fBwritethrough\fP considers a write complete only when it has + been stored in both the cache pool and on the origin LV. + While writethrough may be slower for writes, it is more + resilient if something should happen to a device associated with the +@@ -923,7 +923,7 @@ See \fBlvm.conf\fP(5) for more information about profiles. + . + .TP + .O_compression +-Controls whether compression is enabled or disable for VDO volume. ++Controls whether compression is enabled or disabled for VDO volume. + See \fBlvmvdo\fP(7) for more information about VDO usage. + . + .TP +@@ -948,7 +948,7 @@ messages sent to the log file and/or syslog (if configured). + . + .TP + .O_deduplication +-Controls whether deduplication is enabled or disable for VDO volume. ++Controls whether deduplication is enabled or disabled for VDO volume. + See \fBlvmvdo\fP(7) for more information about VDO usage. + . + .TP +diff --git a/man/lvconvert.8_pregen b/man/lvconvert.8_pregen +index 7ff0d1d79..d5173a651 100644 +--- a/man/lvconvert.8_pregen ++++ b/man/lvconvert.8_pregen +@@ -1750,7 +1750,7 @@ Specifies the cache metadata format used by cache target. + Specifies when writes to a cache LV should be considered complete. + \fBwriteback\fP considers a write complete as soon as it is + stored in the cache pool. +-\fBwritethough\fP considers a write complete only when it has ++\fBwritethrough\fP considers a write complete only when it has + been stored in both the cache pool and on the origin LV. + While writethrough may be slower for writes, it is more + resilient if something should happen to a device associated with the +@@ -1807,7 +1807,7 @@ See \fBlvm.conf\fP(5) for more information about profiles. + . + .TP + .O_compression +-Controls whether compression is enabled or disable for VDO volume. ++Controls whether compression is enabled or disabled for VDO volume. + See \fBlvmvdo\fP(7) for more information about VDO usage. + . + .TP +@@ -1824,7 +1824,7 @@ messages sent to the log file and/or syslog (if configured). + . + .TP + .O_deduplication +-Controls whether deduplication is enabled or disable for VDO volume. ++Controls whether deduplication is enabled or disabled for VDO volume. + See \fBlvmvdo\fP(7) for more information about VDO usage. + . + .TP +@@ -2009,7 +2009,7 @@ Use VDO type volume for pool data volume. + . + .TP + .O_poolmetadata +-The name of a an LV to use for storing pool metadata. ++The name of an LV to use for storing pool metadata. + . + .TP + .O_poolmetadatasize +diff --git a/man/lvcreate.8_pregen b/man/lvcreate.8_pregen +index 5a8c9cc2e..8fc5b34d2 100644 +--- a/man/lvcreate.8_pregen ++++ b/man/lvcreate.8_pregen +@@ -633,7 +633,7 @@ Create a striped LV. + .P + . + Create a raid1 or mirror LV. +-Implicit type is defined by lvm.conf global/mirror_segfault_default. ++Implicit type is defined by lvm.conf global/mirror_segtype_default. + .P + .B lvcreate + .O_mirrors +@@ -1575,7 +1575,7 @@ Specifies the cache metadata format used by cache target. + Specifies when writes to a cache LV should be considered complete. + \fBwriteback\fP considers a write complete as soon as it is + stored in the cache pool. +-\fBwritethough\fP considers a write complete only when it has ++\fBwritethrough\fP considers a write complete only when it has + been stored in both the cache pool and on the origin LV. + While writethrough may be slower for writes, it is more + resilient if something should happen to a device associated with the +@@ -1632,7 +1632,7 @@ See \fBlvm.conf\fP(5) for more information about profiles. + . + .TP + .O_compression +-Controls whether compression is enabled or disable for VDO volume. ++Controls whether compression is enabled or disabled for VDO volume. + See \fBlvmvdo\fP(7) for more information about VDO usage. + . + .TP +@@ -1657,7 +1657,7 @@ messages sent to the log file and/or syslog (if configured). + . + .TP + .O_deduplication +-Controls whether deduplication is enabled or disable for VDO volume. ++Controls whether deduplication is enabled or disabled for VDO volume. + See \fBlvmvdo\fP(7) for more information about VDO usage. + . + .TP +@@ -1847,7 +1847,7 @@ This is useful for skipping a potentially long and resource intensive initial + sync of an empty mirror/raid1/raid4/raid5 and raid10 LV. + This option is not valid for raid6, because raid6 relies on proper parity + (P and Q Syndromes) being created during initial synchronization in order +-to reconstruct proper user date in case of device failures. ++to reconstruct proper user data in case of device failures. + raid0 and raid0_meta do not provide any data copies or parity support + and thus do not support initial synchronization. + . +diff --git a/man/lvextend.8_pregen b/man/lvextend.8_pregen +index e52d46fd4..2729d6eda 100644 +--- a/man/lvextend.8_pregen ++++ b/man/lvextend.8_pregen +@@ -713,7 +713,7 @@ This is useful for skipping a potentially long and resource intensive initial + sync of an empty mirror/raid1/raid4/raid5 and raid10 LV. + This option is not valid for raid6, because raid6 relies on proper parity + (P and Q Syndromes) being created during initial synchronization in order +-to reconstruct proper user date in case of device failures. ++to reconstruct proper user data in case of device failures. + raid0 and raid0_meta do not provide any data copies or parity support + and thus do not support initial synchronization. + . +diff --git a/man/lvresize.8_pregen b/man/lvresize.8_pregen +index a1f127a1e..8c1ff4dfd 100644 +--- a/man/lvresize.8_pregen ++++ b/man/lvresize.8_pregen +@@ -639,7 +639,7 @@ This is useful for skipping a potentially long and resource intensive initial + sync of an empty mirror/raid1/raid4/raid5 and raid10 LV. + This option is not valid for raid6, because raid6 relies on proper parity + (P and Q Syndromes) being created during initial synchronization in order +-to reconstruct proper user date in case of device failures. ++to reconstruct proper user data in case of device failures. + raid0 and raid0_meta do not provide any data copies or parity support + and thus do not support initial synchronization. + . +-- +2.51.0 + diff --git a/SOURCES/0048-activating-raid-LV-with-partial-snapshot-is-an-error.patch b/SOURCES/0048-activating-raid-LV-with-partial-snapshot-is-an-error.patch new file mode 100644 index 0000000..2c76d74 --- /dev/null +++ b/SOURCES/0048-activating-raid-LV-with-partial-snapshot-is-an-error.patch @@ -0,0 +1,48 @@ +From 52efa6f5a1a5a9057130d0b3c8acfdb8feff2e22 Mon Sep 17 00:00:00 2001 +From: David Teigland +Date: Mon, 27 Oct 2025 11:01:16 -0500 +Subject: [PATCH] activating raid LV with partial snapshot is an error + +Detect and report this error early in the command, with +a clear message, including a possible remedy. Previously, +the command failed at a lower level, where the message is +confusing or even misleading. + +Old error message: + "Aborting. LV vg/snap1 is incomplete and --activationmode partial was not specified." + +New error message: + "Activating raid LV vg/main requires the removal of partial snapshot vg/snap1." + +(cherry picked from commit 2760e804630a36bab2c3938ce9ac0b08c5e75395) +--- + tools/toollib.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/tools/toollib.c b/tools/toollib.c +index a7384dd60..b9fa67446 100644 +--- a/tools/toollib.c ++++ b/tools/toollib.c +@@ -781,6 +781,19 @@ int lv_change_activate(struct cmd_context *cmd, struct logical_volume *lv, + } + } + ++ if (lv_is_raid(lv) && lv_is_origin(lv) && lv_is_partial(lv)) { ++ struct lv_list *lvl; ++ dm_list_iterate_items(lvl, &lv->vg->lvs) { ++ if (lv_is_cow(lvl->lv) && ++ (lv_origin_lv(lvl->lv) == lv) && ++ lv_is_partial(lvl->lv)) { ++ log_error("Activating raid LV %s requires the removal of partial snapshot %s.", ++ display_lvname(lv), display_lvname(lvl->lv)); ++ return 0; ++ } ++ } ++ } ++ + if (is_change_activating(activate) && + lvmcache_has_duplicate_devs() && + vg_has_duplicate_pvs(lv->vg) && +-- +2.51.1 + diff --git a/SOURCES/0049-lv_manip-show-a-warning-during-classic-snapshot-crea.patch b/SOURCES/0049-lv_manip-show-a-warning-during-classic-snapshot-crea.patch new file mode 100644 index 0000000..b51b006 --- /dev/null +++ b/SOURCES/0049-lv_manip-show-a-warning-during-classic-snapshot-crea.patch @@ -0,0 +1,34 @@ +From a71342640ddf81b73625e55149f1077245ee7412 Mon Sep 17 00:00:00 2001 +From: Heinz Mauelshagen +Date: Mon, 27 Oct 2025 17:37:09 +0100 +Subject: [PATCH 49/51] lv_manip: show a warning during classic snapshot + creation on a RaidLV. + +The RaidLV will fail to activate in case of the loss of any of its snapshots. +Once created, commit 2760e804630a36bab2c3938ce9ac0b08c5e75395 will +catch any loss of such snapshots and provide remedy information. + +(cherry picked from commit ae81b41811ede78b77f6badf0c65c88fa56cc951) +--- + lib/metadata/lv_manip.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c +index 577ffd0b3..e7405f1dc 100644 +--- a/lib/metadata/lv_manip.c ++++ b/lib/metadata/lv_manip.c +@@ -9654,6 +9654,11 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg, + goto revert_new_lv; + } + ++ if (lp->snapshot && origin_lv && lv_is_raid(origin_lv)) { ++ log_warn("WARNING: Loss of snapshot %s will cause the activation of the %s LV %s to fail!", ++ lp->lv_name, lvseg_name(first_seg(origin_lv)), display_lvname(origin_lv)); ++ } ++ + /* Do not scan this LV until properly zeroed/wiped. */ + if (_should_wipe_lv(lp, lv, 0)) + lv->status |= LV_NOSCAN; +-- +2.51.1 + diff --git a/SOURCES/0050-test-add-new-test-for-snapshot-on-raid-creation-acti.patch b/SOURCES/0050-test-add-new-test-for-snapshot-on-raid-creation-acti.patch new file mode 100644 index 0000000..662d6ab --- /dev/null +++ b/SOURCES/0050-test-add-new-test-for-snapshot-on-raid-creation-acti.patch @@ -0,0 +1,67 @@ +From 4ad6776b11103a864b98963c3540e87e13db2450 Mon Sep 17 00:00:00 2001 +From: Heinz Mauelshagen +Date: Mon, 27 Oct 2025 19:12:25 +0100 +Subject: [PATCH 50/51] test: add new test for snapshot on raid + creation/activation warning/error + +(cherry picked from commit 6704ef4012e8c187deaeadb1275e2d80661c3941) +--- + ...shot-create-warning-activate-error-raid.sh | 46 +++++++++++++++++++ + 1 file changed, 46 insertions(+) + create mode 100644 test/shell/snapshot-create-warning-activate-error-raid.sh + +diff --git a/test/shell/snapshot-create-warning-activate-error-raid.sh b/test/shell/snapshot-create-warning-activate-error-raid.sh +new file mode 100644 +index 000000000..c5b65d018 +--- /dev/null ++++ b/test/shell/snapshot-create-warning-activate-error-raid.sh +@@ -0,0 +1,46 @@ ++#!/usr/bin/env bash ++ ++# Copyright (C) 2025 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 ++ ++# Test for classic snapshots of raid throwing warning/error on creation/activation ++ ++ ++. lib/inittest --skip-with-lvmpolld ++ ++aux have_raid 1 3 0 || skip ++ ++aux prepare_devs 2 50 ++ ++# Create Raid1LV and wait for initial sync to finish. ++vgcreate $SHARED $vg "$dev1" "$dev2" ++lvcreate -y --type raid1 -m1 -n $lv1 -L32M $vg ++aux wait_for_sync $vg $lv1 ++ ++# Create classic snapshot of Raid1LV and check for warning message. ++lvcreate -y -s -n snap -L12M $vg/$lv1 "$dev1" 2>&1 | grep 'WARNING: Loss of snapshot ' >/dev/null 2>&1 ++ ++# Disable all LVs and the first PV with the snapshot allocated on. ++vgchange -an $vg ++aux disable_dev "$dev1" ++ ++# Active vg and check for warning message. ++not vgchange -ay $vg 2>&1 | grep -E 'Activating raid LV .* requires the removal of partial snapshot' >/dev/null 2>&1 ++ ++# Remove the snapshot having lost its backing PV. ++lvremove -y $vg/snap ++ ++# Active vg and check for warning message not being displayed. ++vgchange -ay $vg 2>&1 | not grep -E 'Activating raid LV .* requires the removal of partial snapshot' >/dev/null 2>&1 ++ ++ls $DM_DEV_DIR/$vg/$lv1 ++ ++lvremove -y $vg/$lv1 ++vgremove -ff $vg +-- +2.51.1 + diff --git a/SOURCES/0051-WHATS_NEW-update.patch b/SOURCES/0051-WHATS_NEW-update.patch new file mode 100644 index 0000000..857e6fa --- /dev/null +++ b/SOURCES/0051-WHATS_NEW-update.patch @@ -0,0 +1,36 @@ +From 8af5d6dda5a1e29e0fa9e573ca6f6cf69d07aa9b Mon Sep 17 00:00:00 2001 +From: Heinz Mauelshagen +Date: Mon, 27 Oct 2025 19:15:06 +0100 +Subject: [PATCH 51/51] WHATS_NEW: update + +--- + WHATS_NEW | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/WHATS_NEW b/WHATS_NEW +index 41fea1a7a..19442f8c5 100644 +--- a/WHATS_NEW ++++ b/WHATS_NEW +@@ -1,8 +1,19 @@ ++Version 2.03.37 - ++================== ++ Warn on classic snapshot on raid creation and error on activation + test. ++ ++Version 2.03.35 - ++================== ++ Fix unlocking devices file only after all PVs are processed. ++ Avoid creating system.devices when deleting entries. ++ Fix --lockopt handling in lvmlockd when --nolocking is used. ++ + Version 2.03.34 - + ================== + Fix lvmdevices --deldev/--delpvid to error out if devices file not writeable. + Fix lvresize corruption in LV->crypt->FS stack if near crypt min size limit. + Fix autoactivation on top of loop dev PVs to trigger once for change uevents. ++ Add lvmlockd --lockopt repair to reinitialize corrupted sanlock leases. + + Version 2.03.33 - 27th June 2025 + ================================ +-- +2.51.1 + diff --git a/SOURCES/0052-integrity-allow-creating-imeta-with-more-than-one-se.patch b/SOURCES/0052-integrity-allow-creating-imeta-with-more-than-one-se.patch new file mode 100644 index 0000000..8b8f01c --- /dev/null +++ b/SOURCES/0052-integrity-allow-creating-imeta-with-more-than-one-se.patch @@ -0,0 +1,240 @@ +From 48c68c0cc2cef75f6aa1c6a3e68c44b3a806f60a Mon Sep 17 00:00:00 2001 +From: David Teigland +Date: Mon, 13 Oct 2025 14:36:58 -0500 +Subject: [PATCH] integrity: allow creating imeta with more than one segment + +The imeta LV is already permitted to have more than one segment when +extending, so there's no reason to prevent this in the initial state. + +(cherry picked from commit 724747d7729c38133c4d71f96edd6e2be9dd44a0) +--- + lib/metadata/integrity_manip.c | 5 - + test/shell/integrity-imeta-segs.sh | 200 +++++++++++++++++++++++++++++ + 2 files changed, 200 insertions(+), 5 deletions(-) + create mode 100755 test/shell/integrity-imeta-segs.sh + +diff --git a/lib/metadata/integrity_manip.c b/lib/metadata/integrity_manip.c +index 43a9143a5..be2d458b3 100644 +--- a/lib/metadata/integrity_manip.c ++++ b/lib/metadata/integrity_manip.c +@@ -151,11 +151,6 @@ static int _lv_create_integrity_metadata(struct cmd_context *cmd, + return 0; + } + +- if (dm_list_size(&lv->segments) > 1) { +- log_error("Integrity metadata uses more than one segment."); +- return 0; +- } +- + *meta_lv = lv; + return 1; + } +diff --git a/test/shell/integrity-imeta-segs.sh b/test/shell/integrity-imeta-segs.sh +new file mode 100755 +index 000000000..4df1a7dda +--- /dev/null ++++ b/test/shell/integrity-imeta-segs.sh +@@ -0,0 +1,200 @@ ++#!/usr/bin/env bash ++ ++# Copyright (C) 2025 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 ++ ++# Test creating integrity metadata LV requiring multiple LV segments ++ ++SKIP_WITH_LOW_SPACE=256 ++ ++. lib/inittest ++ ++aux have_integrity 1 5 0 || skip ++ ++which mkfs.xfs || skip ++mnt="mnt" ++mkdir -p $mnt ++ ++# Use awk instead of anoyingly long log out from printf ++#printf "%0.sA" {1..16384} >> fileA ++awk 'BEGIN { while (z++ < 16384) printf "A" }' > fileA ++awk 'BEGIN { while (z++ < 16384) printf "B" }' > fileB ++awk 'BEGIN { while (z++ < 16384) printf "C" }' > fileC ++ ++# generate random data ++dd if=/dev/urandom of=randA bs=512K count=2 ++dd if=/dev/urandom of=randB bs=512K count=3 ++dd if=/dev/urandom of=randC bs=512K count=4 ++ ++_prepare_vg() { ++ vgcreate $SHARED $vg "$dev1" "$dev2" ++ pvs ++} ++ ++_add_data_to_lv() { ++ mkfs.xfs -f "$DM_DEV_DIR/$vg/$lv1" ++ ++ mount "$DM_DEV_DIR/$vg/$lv1" $mnt ++ ++ # add original data ++ cp randA $mnt ++ cp randB $mnt ++ cp randC $mnt ++ mkdir $mnt/1 ++ cp fileA $mnt/1 ++ cp fileB $mnt/1 ++ cp fileC $mnt/1 ++ mkdir $mnt/2 ++ cp fileA $mnt/2 ++ cp fileB $mnt/2 ++ cp fileC $mnt/2 ++ ++ umount $mnt ++} ++ ++_verify_data_on_lv() { ++ mount "$DM_DEV_DIR/$vg/$lv1" $mnt ++ ++ diff randA $mnt/randA ++ diff randB $mnt/randB ++ diff randC $mnt/randC ++ diff fileA $mnt/1/fileA ++ diff fileB $mnt/1/fileB ++ diff fileC $mnt/1/fileC ++ diff fileA $mnt/2/fileA ++ diff fileB $mnt/2/fileB ++ diff fileC $mnt/2/fileC ++ ++ umount $mnt ++} ++ ++_replace_data_on_lv() { ++ mount "$DM_DEV_DIR/$vg/$lv1" $mnt ++ ++ rm $mnt/randA ++ rm $mnt/randB ++ rm $mnt/randC ++ rm $mnt/1/fileA ++ rm $mnt/1/fileB ++ rm $mnt/1/fileC ++ rm $mnt/2/fileA ++ rm $mnt/2/fileB ++ rm $mnt/2/fileC ++ ++ cp randA $mnt ++ cp randB $mnt ++ cp randC $mnt ++ cp fileA $mnt/1 ++ cp fileB $mnt/1 ++ cp fileC $mnt/1 ++ cp fileA $mnt/2 ++ cp fileB $mnt/2 ++ cp fileC $mnt/2 ++ ++ umount $mnt ++} ++ ++# Create a raid LV with multi-segment images (based on an example of vg metadata) ++# Strategy: Fragment the PV by creating/removing temporary LVs, causing the raid ++# images to be allocated in multiple non-contiguous segments. When adding integrity, ++# the imeta will likely also need multiple segments due to the fragmented free space. ++ ++# Use smaller extent size to reduce total device size needed ++# With 2MB extents, a 400MB raid LV can have multi-segment images with smaller devices ++aux prepare_devs 2 256 ++vgcreate -s 2m $SHARED $vg "$dev1" "$dev2" ++ ++# Two-phase fragmentation strategy: ++# Phase 1: Create some larger LVs, then create the raid LV which will consume the gaps ++# Phase 2: Create small fragments in the remaining space where imeta will allocate ++ ++# Phase 1: Create large fragments so the raid LV will have 2-3 segments ++lvcreate -n frag1 -L 60M -an $vg "$dev1" ++lvcreate -n frag2 -L 60M -an $vg "$dev2" ++ ++lvcreate -n temp1 -L 80M -an $vg "$dev1" ++lvcreate -n temp2 -L 80M -an $vg "$dev2" ++ ++lvcreate -n frag3 -L 40M -an $vg "$dev1" ++lvcreate -n frag4 -L 40M -an $vg "$dev2" ++ ++# Remove temp1 and temp2, leaving large gaps for the raid LV ++lvremove -y $vg/temp1 $vg/temp2 ++ ++pvs -o+pv_free,pv_used ++ ++# Now create a raid1 LV that will use the large fragmented gaps ++# This will result in raid images with 2 segments ++lvcreate --type raid1 -m1 -n $lv1 -L 120M -an $vg ++ ++lvchange -ay $vg/$lv1 ++_add_data_to_lv ++lvchange -an $vg/$lv1 ++ ++lvs -a -o+devices,seg_count $vg ++ ++# Check if the rimage has multiple segments (should be 2) ++check lv_field $vg/${lv1}_rimage_0 seg_count 2 ++check lv_field $vg/${lv1}_rimage_1 seg_count 2 ++ ++# Phase 2: Now fragment the remaining free space into small gaps for imeta ++# The remaining free space should be ~70MB on each device ++# Create 6MB fragments leaving 6MB gaps ++for i in {1..6}; do ++ lvcreate -n perm${i} -L 6M -an $vg "$dev1" 2>/dev/null || break ++ lvcreate -n temp${i} -L 6M -an $vg "$dev1" 2>/dev/null || break ++done ++ ++for i in {1..6}; do ++ lvcreate -n perm${i}_2 -L 6M -an $vg "$dev2" 2>/dev/null || break ++ lvcreate -n temp${i}_2 -L 6M -an $vg "$dev2" 2>/dev/null || break ++done ++ ++# Remove temp LVs, leaving 6MB (3-extent) gaps ++for i in {1..6}; do ++ lvremove -y $vg/temp${i} 2>/dev/null || true ++ lvremove -y $vg/temp${i}_2 2>/dev/null || true ++done ++ ++pvs -o+pv_free,pv_used ++lvs -a -o+devices,seg_count $vg ++ ++# Now try to add integrity ++# With a 120MB LV, imeta needs ~8MB (4 extents with 2MB extent size) ++# The fragmented free space (only 6MB/3-extent gaps) should cause imeta allocation ++# to require multiple segments. ++lvchange -an $vg/$lv1 ++lvconvert --raidintegrity y $vg/$lv1 ++ ++lvs -a -o+devices $vg ++ ++lvchange -ay $vg/$lv1 ++aux wait_recalc $vg/${lv1}_rimage_0 ++aux wait_recalc $vg/${lv1}_rimage_1 ++_verify_data_on_lv ++lvextend -L+4M $vg/$lv1 ++_verify_data_on_lv ++_replace_data_on_lv ++lvconvert --raidintegrity n $vg/$lv1 ++_verify_data_on_lv ++ ++# Clean up ++lvremove -y $vg/$lv1 || true ++ ++# Remove all fragment LVs ++lvremove -y $vg/frag1 $vg/frag2 $vg/frag3 $vg/frag4 || true ++ ++# Remove all perm LVs ++for i in {1..6}; do ++ lvremove -y $vg/perm${i} 2>/dev/null || true ++ lvremove -y $vg/perm${i}_2 2>/dev/null || true ++done ++ ++vgremove -ff $vg +-- +2.52.0 + diff --git a/SOURCES/0053-lvresize-fix-xfs-size-checks.patch b/SOURCES/0053-lvresize-fix-xfs-size-checks.patch new file mode 100644 index 0000000..0a6b565 --- /dev/null +++ b/SOURCES/0053-lvresize-fix-xfs-size-checks.patch @@ -0,0 +1,350 @@ +From dcda3b48c2f6ca9841d53911d10fe8825f4e1d19 Mon Sep 17 00:00:00 2001 +From: David Teigland +Date: Thu, 11 Dec 2025 14:48:42 -0600 +Subject: [PATCH 53/57] lvresize: fix xfs size checks + +After lvextend with xfs_growfs on a mounted xfs file system, +libblkid FSLASTBLOCK continues to return the original value, +and does not reflect the grown size of the fs. + +If that was followed by lvreduce back to the original LV size, +lvm saw the original fs size in FSLASTBLOCK, and allowed the LV +to shrink back to the original size, even though xfs had grown +and was now using the space. + +Fix this by using the XFS_IOC_FSGEOMETRY ioctl to get the +correct size value for mounted xfs. + +(cherry picked from commit 0b231e3f4e3e60b8ec7bb7e4443583a06f42614e) +--- + lib/device/filesystem.c | 53 +++++++++++++++++++++++--- + lib/device/filesystem.h | 3 +- + lib/metadata/lv_manip.c | 6 +-- + test/shell/lvresize-fs-crypt.sh | 18 +++++++++ + test/shell/lvresize-fs.sh | 67 +++++++++++++++++++++++++++++++++ + test/shell/lvresize-xfs.sh | 67 ++++++++++++++++++++++++++++++++- + 6 files changed, 203 insertions(+), 11 deletions(-) + +diff --git a/lib/device/filesystem.c b/lib/device/filesystem.c +index 6d53ebd24..64e1d9422 100644 +--- a/lib/device/filesystem.c ++++ b/lib/device/filesystem.c +@@ -22,7 +22,21 @@ + + #include + #include ++#include + #include ++#include ++/* including xfs/linux.h causes uuid_t conflicts, so define some types that are needed */ ++/* #include */ ++typedef off_t xfs_off_t; ++typedef uint64_t xfs_ino_t; ++typedef uint32_t xfs_dev_t; ++typedef int64_t xfs_daddr_t; ++typedef __u32 xfs_nlink_t; ++#include ++#ifndef __user ++#define __user ++#endif ++#include + + static const char *_lvresize_fs_helper_path; + +@@ -253,8 +267,36 @@ static int _btrfs_get_mnt(struct fs_info *fsi, dev_t lv_devt) + return ret; + } + +-int fs_get_info(struct cmd_context *cmd, struct logical_volume *lv, +- struct fs_info *fsi, int include_mount) ++static int _xfs_update_size_mounted(struct cmd_context *cmd, struct logical_volume *lv, ++ char *lv_path, struct fs_info *fsi) ++{ ++ struct xfs_fsop_geom geo = { 0 }; ++ int fd; ++ int ret = 0; ++ ++ if ((fd = open(fsi->mount_dir, O_RDONLY)) < 0) { ++ log_error("XFS geometry open error %d for %s %s", errno, lv_path, fsi->mount_dir); ++ return 0; ++ } ++ ++ if (ioctl(fd, XFS_IOC_FSGEOMETRY, &geo)) { ++ log_error("XFS geometry ioctl error %d for %s %s", errno, lv_path, fsi->mount_dir); ++ goto out; ++ } ++ ++ /* replace the potentially wrong value from blkid_probe_lookup_value FSLASTBLOCK */ ++ fsi->fs_last_byte = geo.blocksize * geo.datablocks; ++ ret = 1; ++ ++ log_debug("xfs geometry blocksize %llu datablocks %llu fs_last_byte %llu from %s %s", ++ (unsigned long long)geo.blocksize, (unsigned long long)geo.datablocks, ++ (unsigned long long)fsi->fs_last_byte, lv_path, fsi->mount_dir); ++out: ++ (void)close(fd); ++ return ret; ++} ++ ++int fs_get_info(struct cmd_context *cmd, struct logical_volume *lv, struct fs_info *fsi) + { + char lv_path[PATH_MAX]; + char crypt_path[PATH_MAX] = { 0 }; +@@ -340,14 +382,15 @@ int fs_get_info(struct cmd_context *cmd, struct logical_volume *lv, + st_top = st_lv; + } + +- if (!include_mount) +- return 1; +- + if (!strcmp(fsi->fstype, "btrfs")) + ret = _btrfs_get_mnt(fsi, st_lv.st_rdev); + else + ret = _fs_get_mnt(fsi, st_top.st_rdev); + ++ /* blkid FSLASTBLOCK may be incorrect for mounted xfs */ ++ if (fsi->mounted && !strcmp(fsi->fstype, "xfs")) ++ ret = _xfs_update_size_mounted(cmd, lv, lv_path, fsi); ++ + fsi->unmounted = !fsi->mounted; + return ret; + } +diff --git a/lib/device/filesystem.h b/lib/device/filesystem.h +index 4ba6f0db9..bb43f9a96 100644 +--- a/lib/device/filesystem.h ++++ b/lib/device/filesystem.h +@@ -45,8 +45,7 @@ struct fs_info { + unsigned needs_crypt:1; + }; + +-int fs_get_info(struct cmd_context *cmd, struct logical_volume *lv, +- struct fs_info *fsi, int include_mount); ++int fs_get_info(struct cmd_context *cmd, struct logical_volume *lv, struct fs_info *fsi); + + int fs_extend_script(struct cmd_context *cmd, struct logical_volume *lv, struct fs_info *fsi, char *fsmode); + int fs_reduce_script(struct cmd_context *cmd, struct logical_volume *lv, struct fs_info *fsi, char *fsmode); +diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c +index e7405f1dc..7296f5e66 100644 +--- a/lib/metadata/lv_manip.c ++++ b/lib/metadata/lv_manip.c +@@ -6459,7 +6459,7 @@ static int _fs_reduce(struct cmd_context *cmd, struct logical_volume *lv, + memset(&fsinfo, 0, sizeof(fsinfo)); + memset(&fsinfo2, 0, sizeof(fsinfo)); + +- if (!fs_get_info(cmd, lv, &fsinfo, 1)) ++ if (!fs_get_info(cmd, lv, &fsinfo)) + goto_out; + + if (fsinfo.nofs) { +@@ -6578,7 +6578,7 @@ static int _fs_reduce(struct cmd_context *cmd, struct logical_volume *lv, + * Re-check the fs last block which should now be less than the + * requested (reduced) LV size. + */ +- if (!fs_get_info(cmd, lv, &fsinfo2, 0)) ++ if (!fs_get_info(cmd, lv, &fsinfo2)) + goto_out; + + if (fsinfo.fs_last_byte && (fsinfo2.fs_last_byte > fsinfo.new_size_bytes)) { +@@ -6600,7 +6600,7 @@ static int _fs_extend_check_fsinfo(struct cmd_context *cmd, struct logical_volum + + memset(fsinfo, 0, sizeof(*fsinfo)); + +- if (!fs_get_info(cmd, lv, fsinfo, 1)) ++ if (!fs_get_info(cmd, lv, fsinfo)) + return 0; + + if (fsinfo->nofs) +diff --git a/test/shell/lvresize-fs-crypt.sh b/test/shell/lvresize-fs-crypt.sh +index a56bf6a3e..d4f9de1e0 100644 +--- a/test/shell/lvresize-fs-crypt.sh ++++ b/test/shell/lvresize-fs-crypt.sh +@@ -97,6 +97,24 @@ umount "$mount_dir" + cryptsetup close $cr + lvremove -f $vg/$lv + ++# lvextend+lvreduce xfs on LUKS1 ++lvcreate -n $lv -L 320M $vg ++echo 93R4P4pIqAH8 | cryptsetup luksFormat -i1 --type luks1 "$DM_DEV_DIR/$vg/$lv" ++echo 93R4P4pIqAH8 | cryptsetup luksOpen "$DM_DEV_DIR/$vg/$lv" $cr ++mkfs.xfs /dev/mapper/$cr ++mount /dev/mapper/$cr "$mount_dir" ++dd if=/dev/zero of="$mount_dir/zeros1" bs=1M count=20 oflag=direct ++df --output=size "$mount_dir" |tee df1 ++lvextend -L+136M --fs resize $vg/$lv ++check lv_field $vg/$lv lv_size "456.00m" ++df --output=size "$mount_dir" |tee df2 ++not diff df1 df2 ++not lvresize -L 320M $vg/$lv ++not lvresize -r -L 320M $vg/$lv ++umount "$mount_dir" ++cryptsetup close $cr ++lvremove -f $vg/$lv ++ + # lvextend ext4 on plain crypt (no header) + lvcreate -n $lv -L 256M $vg + echo 93R4P4pIqAH8 | cryptsetup create $cr "$DM_DEV_DIR/$vg/$lv" +diff --git a/test/shell/lvresize-fs.sh b/test/shell/lvresize-fs.sh +index 4bcbb9ca2..266f18bc1 100644 +--- a/test/shell/lvresize-fs.sh ++++ b/test/shell/lvresize-fs.sh +@@ -700,5 +700,72 @@ blkid -p "$DM_DEV_DIR/$vg/$lv" | grep FSSIZE && { + lvreduce -L16m $vg/$lv + check lv_field $vg/$lv lv_size "16.00m" + } ++lvremove -y $vg/$lv ++ ++############################### ++# ++# lvextend followed by lvreduce ++# ++############################### ++ ++# mounted, fs resized ++lvcreate -n $lv -L 40M $vg ++mkfs.ext4 "$DM_DEV_DIR/$vg/$lv" ++mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir" ++dd if=/dev/zero of="$mount_dir/zeros1" bs=1M count=10 oflag=direct ++lvresize --yes -r -L 50M $vg/$lv ++not lvresize --yes -L 40M $vg/$lv ++lvresize --yes -r -L 40M $vg/$lv ++umount "$mount_dir" ++lvchange -an $vg/$lv ++lvremove $vg/$lv ++ ++# unmounted, fs resized ++lvcreate -n $lv -L 40M $vg ++mkfs.ext4 "$DM_DEV_DIR/$vg/$lv" ++mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir" ++dd if=/dev/zero of="$mount_dir/zeros1" bs=1M count=10 oflag=direct ++umount "$mount_dir" ++lvresize --yes -r -L 50M $vg/$lv ++not lvresize --yes -L 40M $vg/$lv ++lvresize --yes -r -L 40M $vg/$lv ++lvchange -an $vg/$lv ++lvremove $vg/$lv ++ ++# mounted, fs not resized ++lvcreate -n $lv -L 40M $vg ++mkfs.ext4 "$DM_DEV_DIR/$vg/$lv" ++mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir" ++dd if=/dev/zero of="$mount_dir/zeros1" bs=1M count=10 oflag=direct ++df --output=size "$mount_dir" |tee df1 ++lvresize --yes -L 50M $vg/$lv ++check lv_field $vg/$lv lv_size "50.00m" ++lvresize --yes -L 40M $vg/$lv ++check lv_field $vg/$lv lv_size "40.00m" ++df --output=size "$mount_dir" |tee df2 ++# fs size unchanged ++diff df1 df2 ++umount "$mount_dir" ++lvchange -an $vg/$lv ++lvremove $vg/$lv ++ ++# unmounted, fs not resized ++lvcreate -n $lv -L 40M $vg ++mkfs.ext4 "$DM_DEV_DIR/$vg/$lv" ++mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir" ++dd if=/dev/zero of="$mount_dir/zeros1" bs=1M count=10 oflag=direct ++df --output=size "$mount_dir" |tee df1 ++umount "$mount_dir" ++lvresize --yes -L 50M $vg/$lv ++check lv_field $vg/$lv lv_size "50.00m" ++lvresize --yes -L 40M $vg/$lv ++check lv_field $vg/$lv lv_size "40.00m" ++# fs size unchanged ++mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir" ++df --output=size "$mount_dir" |tee df2 ++diff df1 df2 ++umount "$mount_dir" ++lvchange -an $vg/$lv ++lvremove $vg/$lv + + vgremove -ff $vg +diff --git a/test/shell/lvresize-xfs.sh b/test/shell/lvresize-xfs.sh +index 4c4ed15e7..ef87b1b3a 100644 +--- a/test/shell/lvresize-xfs.sh ++++ b/test/shell/lvresize-xfs.sh +@@ -19,7 +19,7 @@ which xfs_growfs || skip + + aux have_fsinfo || skip "Test needs --fs checksize support" + +-aux prepare_vg 1 500 ++aux prepare_vg 1 600 + + mount_dir="mnt_lvresize_fs" + mkdir -p "$mount_dir" +@@ -242,6 +242,71 @@ umount "$mount_dir" + + lvremove -f $vg/$lv + ++############################### ++# ++# lvextend followed by lvreduce ++# ++############################### ++ ++# mounted, fs resized ++lvcreate -n $lv -L 400M $vg ++mkfs.xfs "$DM_DEV_DIR/$vg/$lv" ++mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir" ++dd if=/dev/zero of="$mount_dir/zeros1" bs=1M count=20 oflag=direct ++lvresize --yes -r -L 500M $vg/$lv ++not lvresize --yes -r -L 400M $vg/$lv ++not lvresize --yes -L 400M $vg/$lv ++umount "$mount_dir" ++lvchange -an $vg/$lv ++lvremove $vg/$lv ++ ++# unmounted, fs resized ++lvcreate -n $lv -L 400M $vg ++mkfs.xfs "$DM_DEV_DIR/$vg/$lv" ++mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir" ++dd if=/dev/zero of="$mount_dir/zeros1" bs=1M count=20 oflag=direct ++umount "$mount_dir" ++lvresize --yes -r -L 500M $vg/$lv ++not lvresize --yes -r -L 400M $vg/$lv ++not lvresize --yes -L 400M $vg/$lv ++lvchange -an $vg/$lv ++lvremove $vg/$lv ++ ++# mounted, fs not resized ++lvcreate -n $lv -L 400M $vg ++mkfs.xfs "$DM_DEV_DIR/$vg/$lv" ++mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir" ++dd if=/dev/zero of="$mount_dir/zeros1" bs=1M count=20 oflag=direct ++df --output=size "$mount_dir" |tee df1 ++lvresize --yes -L 500M $vg/$lv ++check lv_field $vg/$lv lv_size "500.00m" ++lvresize --yes -L 400M $vg/$lv ++check lv_field $vg/$lv lv_size "400.00m" ++df --output=size "$mount_dir" |tee df2 ++# fs size unchanged ++diff df1 df2 ++umount "$mount_dir" ++lvchange -an $vg/$lv ++lvremove $vg/$lv ++ ++# unmounted, fs not resized ++lvcreate -n $lv -L 400M $vg ++mkfs.xfs "$DM_DEV_DIR/$vg/$lv" ++mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir" ++dd if=/dev/zero of="$mount_dir/zeros1" bs=1M count=20 oflag=direct ++df --output=size "$mount_dir" |tee df1 ++umount "$mount_dir" ++lvresize --yes -L 500M $vg/$lv ++check lv_field $vg/$lv lv_size "500.00m" ++lvresize --yes -L 400M $vg/$lv ++check lv_field $vg/$lv lv_size "400.00m" ++# fs size unchanged ++mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir" ++df --output=size "$mount_dir" |tee df2 ++diff df1 df2 ++umount "$mount_dir" ++lvchange -an $vg/$lv ++lvremove $vg/$lv + + ########################################################## + # +-- +2.52.0 + diff --git a/SOURCES/0054-configure-check-for-xfs-header-file.patch b/SOURCES/0054-configure-check-for-xfs-header-file.patch new file mode 100644 index 0000000..d2cd5a6 --- /dev/null +++ b/SOURCES/0054-configure-check-for-xfs-header-file.patch @@ -0,0 +1,37 @@ +From f533eab471f78f27c86d9b88cf2ba66df924f3ea Mon Sep 17 00:00:00 2001 +From: Zdenek Kabelac +Date: Sun, 14 Dec 2025 17:15:37 +0100 +Subject: [PATCH 54/57] configure: check for xfs header file + +Check if xfs/xfs.h is available. + +(cherry picked from commit 127774ff1bf1a471017b1ae91786eb4e1c2edd82) +--- + configure.ac | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/configure.ac b/configure.ac +index 11a735af5..89ec0ea9c 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -101,6 +101,7 @@ AC_CHECK_HEADERS([assert.h ctype.h dirent.h errno.h fcntl.h float.h \ + unistd.h], , [AC_MSG_ERROR(bailing out)]) + + AC_CHECK_HEADERS(termios.h sys/statvfs.h sys/timerfd.h sys/vfs.h linux/magic.h linux/fiemap.h) ++AC_CHECK_HEADERS(xfs/xfs.h, LVM_NO_XFS_WARN=, LVM_NO_XFS_WARN=y, [#define _GNU_SOURCE 1]) + AC_CHECK_HEADERS(libaio.h,LVM_NEEDS_LIBAIO_WARN=,LVM_NEEDS_LIBAIO_WARN=y) + AS_CASE(["$host_os"], + [linux*], [AC_CHECK_HEADERS([asm/byteorder.h linux/fs.h malloc.h], [], [AC_MSG_ERROR(bailing out)])], +@@ -2126,6 +2127,9 @@ AS_IF([test -n "$VDO_CONFIGURE_WARN"], + AS_IF([test -n "$LVM_NEEDS_LIBAIO_WARN"], + [AC_MSG_WARN([Only libdm part can be build without libaio: make [[install_]]device-mapper])]) + ++AS_IF([test -n "$LVM_NO_XFS_WARN"], ++ [AC_MSG_WARN(['lvextend --resizefs' is less capable without xfs/xfs.h (see package: xfsprogs devel)])]) ++ + AS_IF([test "$ODIRECT" != "yes"], + [AC_MSG_WARN([O_DIRECT disabled: low-memory pvmove may lock up])]) + +-- +2.52.0 + diff --git a/SOURCES/0055-log-add-string.h.patch b/SOURCES/0055-log-add-string.h.patch new file mode 100644 index 0000000..edb6ee7 --- /dev/null +++ b/SOURCES/0055-log-add-string.h.patch @@ -0,0 +1,27 @@ +From 9248e4fa05534a0865a7fad4b0bb76ca85c4dd55 Mon Sep 17 00:00:00 2001 +From: Zdenek Kabelac +Date: Sun, 14 Dec 2025 21:54:29 +0100 +Subject: [PATCH 55/57] log: add string.h + +Header file is using strerror() from . + +(cherry picked from commit e8d744e8bdb8386ab5754015e6511d0431d76f04) +--- + lib/log/log.h | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/lib/log/log.h b/lib/log/log.h +index 6efe5a66b..287db00e5 100644 +--- a/lib/log/log.h ++++ b/lib/log/log.h +@@ -38,6 +38,7 @@ + */ + + #include ++#include + + #define EUNCLASSIFIED -1 /* Generic error code */ + +-- +2.52.0 + diff --git a/SOURCES/0056-filesystem-refactor-code-working-with-xfs.patch b/SOURCES/0056-filesystem-refactor-code-working-with-xfs.patch new file mode 100644 index 0000000..fb3f4ea --- /dev/null +++ b/SOURCES/0056-filesystem-refactor-code-working-with-xfs.patch @@ -0,0 +1,208 @@ +From 077eaef48b2d257e94feb1caa3825fa5a5da14e6 Mon Sep 17 00:00:00 2001 +From: Zdenek Kabelac +Date: Sun, 14 Dec 2025 17:14:08 +0100 +Subject: [PATCH 56/57] filesystem: refactor code working with xfs + +Move XFS ioctl code to separate filesystem_xfs.c file. +Remove hackish way of including xfs headers. + +When xfs/xfs.h is missing, continue running without checking +mounted filesystem size. + +(cherry picked from commit 1e9efc72cfed277e6885e201affbc47a2edbf576) +--- + lib/Makefile.in | 1 + + lib/device/filesystem.c | 48 +++-------------------------- + lib/device/filesystem.h | 10 +++++- + lib/device/filesystem_xfs.c | 61 +++++++++++++++++++++++++++++++++++++ + 4 files changed, 76 insertions(+), 44 deletions(-) + create mode 100644 lib/device/filesystem_xfs.c + +diff --git a/lib/Makefile.in b/lib/Makefile.in +index 8424ac952..8620eaaff 100644 +--- a/lib/Makefile.in ++++ b/lib/Makefile.in +@@ -40,6 +40,7 @@ SOURCES =\ + device/dev-luks.c \ + device/dev-dasd.c \ + device/dev-lvm1-pool.c \ ++ device/filesystem_xfs.c \ + device/filesystem.c \ + device/online.c \ + device/parse_vpd.c \ +diff --git a/lib/device/filesystem.c b/lib/device/filesystem.c +index 64e1d9422..f1add62f9 100644 +--- a/lib/device/filesystem.c ++++ b/lib/device/filesystem.c +@@ -19,24 +19,12 @@ + #include "lib/display/display.h" + #include "lib/misc/lvm-exec.h" + #include "lib/activate/dev_manager.h" ++#include "lib/commands/toolcontext.h" + + #include + #include +-#include + #include + #include +-/* including xfs/linux.h causes uuid_t conflicts, so define some types that are needed */ +-/* #include */ +-typedef off_t xfs_off_t; +-typedef uint64_t xfs_ino_t; +-typedef uint32_t xfs_dev_t; +-typedef int64_t xfs_daddr_t; +-typedef __u32 xfs_nlink_t; +-#include +-#ifndef __user +-#define __user +-#endif +-#include + + static const char *_lvresize_fs_helper_path; + +@@ -267,34 +255,6 @@ static int _btrfs_get_mnt(struct fs_info *fsi, dev_t lv_devt) + return ret; + } + +-static int _xfs_update_size_mounted(struct cmd_context *cmd, struct logical_volume *lv, +- char *lv_path, struct fs_info *fsi) +-{ +- struct xfs_fsop_geom geo = { 0 }; +- int fd; +- int ret = 0; +- +- if ((fd = open(fsi->mount_dir, O_RDONLY)) < 0) { +- log_error("XFS geometry open error %d for %s %s", errno, lv_path, fsi->mount_dir); +- return 0; +- } +- +- if (ioctl(fd, XFS_IOC_FSGEOMETRY, &geo)) { +- log_error("XFS geometry ioctl error %d for %s %s", errno, lv_path, fsi->mount_dir); +- goto out; +- } +- +- /* replace the potentially wrong value from blkid_probe_lookup_value FSLASTBLOCK */ +- fsi->fs_last_byte = geo.blocksize * geo.datablocks; +- ret = 1; +- +- log_debug("xfs geometry blocksize %llu datablocks %llu fs_last_byte %llu from %s %s", +- (unsigned long long)geo.blocksize, (unsigned long long)geo.datablocks, +- (unsigned long long)fsi->fs_last_byte, lv_path, fsi->mount_dir); +-out: +- (void)close(fd); +- return ret; +-} + + int fs_get_info(struct cmd_context *cmd, struct logical_volume *lv, struct fs_info *fsi) + { +@@ -388,8 +348,10 @@ int fs_get_info(struct cmd_context *cmd, struct logical_volume *lv, struct fs_in + ret = _fs_get_mnt(fsi, st_top.st_rdev); + + /* blkid FSLASTBLOCK may be incorrect for mounted xfs */ +- if (fsi->mounted && !strcmp(fsi->fstype, "xfs")) +- ret = _xfs_update_size_mounted(cmd, lv, lv_path, fsi); ++ if (fsi->mounted && !strcmp(fsi->fstype, "xfs")) { ++ if (!(ret = fs_xfs_update_size_mounted(cmd, lv, lv_path, fsi))) ++ stack; ++ } + + fsi->unmounted = !fsi->mounted; + return ret; +diff --git a/lib/device/filesystem.h b/lib/device/filesystem.h +index bb43f9a96..c66b47995 100644 +--- a/lib/device/filesystem.h ++++ b/lib/device/filesystem.h +@@ -15,9 +15,13 @@ + #ifndef _FILESYSTEM_H + #define _FILESYSTEM_H + +-#include "lib/commands/toolcontext.h" + #include "lib/device/device.h" + ++#include /* PATH_MAX */ ++ ++struct cmd_context; ++struct logical_volume; ++ + #define FSTYPE_MAX 16 + #define UUID_LEN 37 + +@@ -54,4 +58,8 @@ int crypt_resize_script(struct cmd_context *cmd, struct logical_volume *lv, stru + int fs_mount_state_is_misnamed(struct cmd_context *cmd, struct logical_volume *lv, char *lv_path, char *fstype); + int lv_crypt_is_active(struct cmd_context *cmd, char *lv_path); + ++/* filesystem_xfs.c */ ++int fs_xfs_update_size_mounted(struct cmd_context *cmd, struct logical_volume *lv, ++ char *lv_path, struct fs_info *fsi); ++ + #endif +diff --git a/lib/device/filesystem_xfs.c b/lib/device/filesystem_xfs.c +new file mode 100644 +index 000000000..61252fe16 +--- /dev/null ++++ b/lib/device/filesystem_xfs.c +@@ -0,0 +1,61 @@ ++/* ++ * Copyright (C) 2025 Red Hat, Inc. All rights reserved. ++ * ++ * This file is part of LVM2. ++ * ++ * 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 Lesser General Public License v.2.1. ++ * ++ * You should have received a copy of the GNU Lesser 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 ++ */ ++ ++#include "filesystem.h" ++#include "lib/log/lvm-logging.h" ++ ++#ifdef HAVE_XFS_XFS_H ++ ++#include ++ ++int fs_xfs_update_size_mounted(struct cmd_context *cmd, struct logical_volume *lv, ++ char *lv_path, struct fs_info *fsi) ++{ ++ struct xfs_fsop_geom geo = { 0 }; ++ int ret = 0; ++ int fd; ++ ++ if ((fd = open(fsi->mount_dir, O_RDONLY)) < 0) { ++ log_sys_error("XFS geometry open", fsi->mount_dir); ++ return 0; ++ } ++ ++ if (ioctl(fd, XFS_IOC_FSGEOMETRY, &geo)) { ++ log_sys_error("XFS geometry ioctl", fsi->mount_dir); ++ goto out; ++ } ++ ++ /* replace the potentially wrong value from blkid_probe_lookup_value FSLASTBLOCK */ ++ fsi->fs_last_byte = geo.blocksize * geo.datablocks; ++ ret = 1; ++ ++ log_debug("xfs geometry blocksize %llu datablocks %llu fs_last_byte %llu from %s %s", ++ (unsigned long long)geo.blocksize, (unsigned long long)geo.datablocks, ++ (unsigned long long)fsi->fs_last_byte, lv_path, fsi->mount_dir); ++out: ++ (void)close(fd); ++ ++ return ret; ++} ++ ++#else /* !HAVE_XFS_XFS_H */ ++ ++int fs_xfs_update_size_mounted(struct cmd_context *cmd, struct logical_volume *lv, ++ char *lv_path, struct fs_info *fsi) ++{ ++ log_debug("No XFS support, continuing WITHOUT reading XFS geometry."); ++ return 1; ++} ++ ++#endif +-- +2.52.0 + diff --git a/SOURCES/0057-lib-rename-uuid.c-to-id.c.patch b/SOURCES/0057-lib-rename-uuid.c-to-id.c.patch new file mode 100644 index 0000000..db237d4 --- /dev/null +++ b/SOURCES/0057-lib-rename-uuid.c-to-id.c.patch @@ -0,0 +1,210 @@ +From 86812cc39d76f615af43d165c0117cae0c844129 Mon Sep 17 00:00:00 2001 +From: Zdenek Kabelac +Date: Sun, 14 Dec 2025 17:13:54 +0100 +Subject: [PATCH 1/2] lib: rename uuid.c to id.c + +Use id.c to better match function naming in id.h. +uuid/uuid.h is public header file, so using lib/id/id.c +avoids potential naming collision with system uuid.h file. + +(cherry picked from commit fe90043412f010957b6c09352a64e56a64c9b2c5) +--- + lib/Makefile.in | 2 +- + lib/cache/lvmcache.h | 2 +- + lib/device/device.h | 2 +- + lib/format_text/format-text.c | 2 +- + lib/format_text/layout.h | 2 +- + lib/{uuid/uuid.c => id/id.c} | 2 +- + lib/{uuid/uuid.h => id/id.h} | 6 +++--- + lib/label/label.h | 2 +- + lib/locking/locking.h | 2 +- + lib/metadata/metadata-exported.h | 2 +- + lib/metadata/pv.h | 2 +- + lib/metadata/vg.h | 2 +- + 12 files changed, 14 insertions(+), 14 deletions(-) + rename lib/{uuid/uuid.c => id/id.c} (99%) + rename lib/{uuid/uuid.h => id/id.h} (93%) + +diff --git a/lib/Makefile.in b/lib/Makefile.in +index 8620eaaff..002a9ec46 100644 +--- a/lib/Makefile.in ++++ b/lib/Makefile.in +@@ -70,6 +70,7 @@ SOURCES =\ + format_text/import_vsn1.c \ + format_text/text_label.c \ + freeseg/freeseg.c \ ++ id/id.c \ + label/label.c \ + label/hints.c \ + locking/file_locking.c \ +@@ -115,7 +116,6 @@ SOURCES =\ + snapshot/snapshot.c \ + striped/striped.c \ + thin/thin.c \ +- uuid/uuid.c \ + zero/zero.c + + ifeq ("@DEVMAPPER@", "yes") +diff --git a/lib/cache/lvmcache.h b/lib/cache/lvmcache.h +index 9db5268dd..0468a6318 100644 +--- a/lib/cache/lvmcache.h ++++ b/lib/cache/lvmcache.h +@@ -18,7 +18,7 @@ + + #include "lib/device/dev-cache.h" + #include "lib/device/dev-type.h" +-#include "lib/uuid/uuid.h" ++#include "lib/id/id.h" + #include "lib/label/label.h" + #include "lib/locking/locking.h" + +diff --git a/lib/device/device.h b/lib/device/device.h +index 8c3cb53b0..35ec3712c 100644 +--- a/lib/device/device.h ++++ b/lib/device/device.h +@@ -17,7 +17,7 @@ + #define _LVM_DEVICE_H + + #include "base/data-struct/list.h" +-#include "lib/uuid/uuid.h" ++#include "lib/id/id.h" + + #include + #include +diff --git a/lib/format_text/format-text.c b/lib/format_text/format-text.c +index d2c99f6bb..615b92df9 100644 +--- a/lib/format_text/format-text.c ++++ b/lib/format_text/format-text.c +@@ -23,7 +23,7 @@ + #include "lib/display/display.h" + #include "lib/commands/toolcontext.h" + #include "lib/misc/lvm-string.h" +-#include "lib/uuid/uuid.h" ++#include "lib/id/id.h" + #include "lib/misc/crc.h" + #include "lib/mm/xlate.h" + #include "lib/label/label.h" +diff --git a/lib/format_text/layout.h b/lib/format_text/layout.h +index 2ef35b3af..2858f39c2 100644 +--- a/lib/format_text/layout.h ++++ b/lib/format_text/layout.h +@@ -20,7 +20,7 @@ + #include "lib/metadata/metadata.h" + #include "lib/format_text/format-text.h" + #include "lib/cache/lvmcache.h" +-#include "lib/uuid/uuid.h" ++#include "lib/id/id.h" + + /* + * PV header extension versions: +diff --git a/lib/uuid/uuid.c b/lib/id/id.c +similarity index 99% +rename from lib/uuid/uuid.c +rename to lib/id/id.c +index 6f7acd2bd..b52121cd9 100644 +--- a/lib/uuid/uuid.c ++++ b/lib/id/id.c +@@ -13,8 +13,8 @@ + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + ++#include "lib/id/id.h" + #include "lib/misc/lib.h" +-#include "lib/uuid/uuid.h" + #include "lib/misc/lvm-wrappers.h" + + #include +diff --git a/lib/uuid/uuid.h b/lib/id/id.h +similarity index 93% +rename from lib/uuid/uuid.h +rename to lib/id/id.h +index 5dad2548a..8e19dff0f 100644 +--- a/lib/uuid/uuid.h ++++ b/lib/id/id.h +@@ -1,6 +1,6 @@ + /* + * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. +- * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2004-2025 Red Hat, Inc. All rights reserved. + * + * This file is part of LVM2. + * +@@ -13,8 +13,8 @@ + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +-#ifndef _LVM_UUID_H +-#define _LVM_UUID_H ++#ifndef _LVM_ID_H ++#define _LVM_ID_H + + #define ID_LEN 32 + +diff --git a/lib/label/label.h b/lib/label/label.h +index 4c224dc50..e17f8c8ed 100644 +--- a/lib/label/label.h ++++ b/lib/label/label.h +@@ -16,7 +16,7 @@ + #ifndef _LVM_LABEL_H + #define _LVM_LABEL_H + +-#include "lib/uuid/uuid.h" ++#include "lib/id/id.h" + #include "lib/device/device.h" + #include "lib/device/bcache.h" + +diff --git a/lib/locking/locking.h b/lib/locking/locking.h +index a60935d52..487139a06 100644 +--- a/lib/locking/locking.h ++++ b/lib/locking/locking.h +@@ -16,7 +16,7 @@ + #ifndef _LVM_LOCKING_H + #define _LVM_LOCKING_H + +-#include "lib/uuid/uuid.h" ++#include "lib/id/id.h" + #include "lib/config/config.h" + + struct logical_volume; +diff --git a/lib/metadata/metadata-exported.h b/lib/metadata/metadata-exported.h +index 3752caf1e..7ec81f27d 100644 +--- a/lib/metadata/metadata-exported.h ++++ b/lib/metadata/metadata-exported.h +@@ -21,7 +21,7 @@ + #ifndef _LVM_METADATA_EXPORTED_H + #define _LVM_METADATA_EXPORTED_H + +-#include "lib/uuid/uuid.h" ++#include "lib/id/id.h" + #include "lib/metadata/pv.h" + #include "lib/metadata/vg.h" + #include "lib/metadata/lv.h" +diff --git a/lib/metadata/pv.h b/lib/metadata/pv.h +index ee2bd853b..7195f9a2d 100644 +--- a/lib/metadata/pv.h ++++ b/lib/metadata/pv.h +@@ -15,7 +15,7 @@ + #ifndef _LVM_PV_H + #define _LVM_PV_H + +-#include "lib/uuid/uuid.h" ++#include "lib/id/id.h" + #include "device_mapper/all.h" + + struct device; +diff --git a/lib/metadata/vg.h b/lib/metadata/vg.h +index 92a15ef2f..0f5adb6ee 100644 +--- a/lib/metadata/vg.h ++++ b/lib/metadata/vg.h +@@ -15,7 +15,7 @@ + #ifndef _LVM_VG_H + #define _LVM_VG_H + +-#include "lib/uuid/uuid.h" ++#include "lib/id/id.h" + #include "device_mapper/all.h" + + struct cmd_context; +-- +2.52.0 + diff --git a/SOURCES/0058-autoreconf-reconfigure.patch b/SOURCES/0058-autoreconf-reconfigure.patch new file mode 100644 index 0000000..578185f --- /dev/null +++ b/SOURCES/0058-autoreconf-reconfigure.patch @@ -0,0 +1,113 @@ +From 5c44e8301451e0bace56c5f1400f11f4758d2aed Mon Sep 17 00:00:00 2001 +From: Zdenek Kabelac +Date: Sun, 14 Dec 2025 17:16:22 +0100 +Subject: [PATCH 2/2] autoreconf: reconfigure + +Regenerate configure and configure.h.in after adding XFS header check. +--- + aclocal.m4 | 8 ++++---- + configure | 28 ++++++++++++++++++++++++++++ + include/configure.h.in | 3 +++ + 3 files changed, 35 insertions(+), 4 deletions(-) + +diff --git a/aclocal.m4 b/aclocal.m4 +index 5f3a3e9c4..fa488e1f8 100644 +--- a/aclocal.m4 ++++ b/aclocal.m4 +@@ -1,6 +1,6 @@ +-# generated automatically by aclocal 1.17 -*- Autoconf -*- ++# generated automatically by aclocal 1.18.1 -*- Autoconf -*- + +-# Copyright (C) 1996-2024 Free Software Foundation, Inc. ++# Copyright (C) 1996-2025 Free Software Foundation, Inc. + + # This file is free software; the Free Software Foundation + # gives unlimited permission to copy and/or distribute it, +@@ -422,7 +422,7 @@ AS_IF([test "$AS_TR_SH([with_]m4_tolower([$1]))" = "yes"], + [AC_DEFINE([HAVE_][$1], 1, [Enable ]m4_tolower([$1])[ support])]) + ])dnl PKG_HAVE_DEFINE_WITH_MODULES + +-# Copyright (C) 1999-2024 Free Software Foundation, Inc. ++# Copyright (C) 1999-2025 Free Software Foundation, Inc. + # + # This file is free software; the Free Software Foundation + # gives unlimited permission to copy and/or distribute it, +@@ -792,7 +792,7 @@ for i in list(range(0, 4)): minverhex = (minverhex << 8) + minver[[i]] + sys.exit(sys.hexversion < minverhex)" + AS_IF([AM_RUN_LOG([$1 -c "$prog"])], [$3], [$4])]) + +-# Copyright (C) 2001-2024 Free Software Foundation, Inc. ++# Copyright (C) 2001-2025 Free Software Foundation, Inc. + # + # This file is free software; the Free Software Foundation + # gives unlimited permission to copy and/or distribute it, +diff --git a/configure b/configure +index 342bd0047..e3eb37ff6 100755 +--- a/configure ++++ b/configure +@@ -6921,6 +6921,20 @@ then : + + fi + ++ for ac_header in xfs/xfs.h ++do : ++ ac_fn_c_check_header_compile "$LINENO" "xfs/xfs.h" "ac_cv_header_xfs_xfs_h" "#define _GNU_SOURCE 1 ++" ++if test "x$ac_cv_header_xfs_xfs_h" = xyes ++then : ++ printf "%s\n" "#define HAVE_XFS_XFS_H 1" >>confdefs.h ++ LVM_NO_XFS_WARN= ++else case e in #( ++ e) LVM_NO_XFS_WARN=y ;; ++esac ++fi ++ ++done + for ac_header in libaio.h + do : + ac_fn_c_check_header_compile "$LINENO" "libaio.h" "ac_cv_header_libaio_h" "$ac_includes_default" +@@ -12183,6 +12197,14 @@ then : + test $ac_status = 0; }; then + LOCKDSANLOCK_SUPPORT=400 + fi ++ if test -n "$PKG_CONFIG" && \ ++ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libsanlock_client >= 4.1.0\""; } >&5 ++ ($PKG_CONFIG --exists --print-errors "libsanlock_client >= 4.1.0") 2>&5 ++ ac_status=$? ++ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 ++ test $ac_status = 0; }; then ++ LOCKDSANLOCK_SUPPORT=410 ++fi + + pkg_failed=no + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libsanlock_client >= 3.7.0" >&5 +@@ -18224,6 +18246,12 @@ then : + printf "%s\n" "$as_me: WARNING: Only libdm part can be build without libaio: make [install_]device-mapper" >&2;} + fi + ++if test -n "$LVM_NO_XFS_WARN" ++then : ++ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: 'lvextend --resizefs' is less capable without xfs/xfs.h (see package: xfsprogs devel)" >&5 ++printf "%s\n" "$as_me: WARNING: 'lvextend --resizefs' is less capable without xfs/xfs.h (see package: xfsprogs devel)" >&2;} ++fi ++ + if test "$ODIRECT" != "yes" + then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: O_DIRECT disabled: low-memory pvmove may lock up" >&5 +diff --git a/include/configure.h.in b/include/configure.h.in +index 3fe1dc85b..eee47a36d 100644 +--- a/include/configure.h.in ++++ b/include/configure.h.in +@@ -549,6 +549,9 @@ + /* Define to 1 if 'vfork' works. */ + #undef HAVE_WORKING_VFORK + ++/* Define to 1 if you have the header file. */ ++#undef HAVE_XFS_XFS_H ++ + /* Define to 1 if the system has the type '_Bool'. */ + #undef HAVE__BOOL + +-- +2.52.0 + diff --git a/SPECS/lvm2.spec b/SPECS/lvm2.spec index ec696a5..6dfe8dd 100644 --- a/SPECS/lvm2.spec +++ b/SPECS/lvm2.spec @@ -1,4 +1,4 @@ -%global device_mapper_version 1.02.206 +%global device_mapper_version 1.02.207 %global enable_cache 1 %global enable_lvmdbusd 1 @@ -50,11 +50,11 @@ Name: lvm2 %if 0%{?rhel} Epoch: %{rhel} %endif -Version: 2.03.32 +Version: 2.03.33 %if 0%{?from_snapshot} Release: 0.1.20211115git%{shortcommit}%{?dist}%{?rel_suffix} %else -Release: 2%{?dist}%{?rel_suffix} +Release: 4%{?dist}%{?rel_suffix} %endif License: GPL-2.0-only URL: https://sourceware.org/lvm2 @@ -70,15 +70,59 @@ Patch4: 0004-Revert-dm-udev-rules-don-t-export-and-save-DM_SUSPEN.patch Patch5: 0005-Revert-11-dm-lvm.rules-don-t-restore-DM_UDEV_DISABLE.patch Patch6: 0006-Revert-10-dm-rules-don-t-restore-DM_UDEV_DISABLE_OTH.patch Patch7: 0007-WHATS_NEW_DM-update.patch -# RHEL-94577: -Patch8: 0008-lvmlockd-fix-hosts-check-for-vgremove.patch -Patch9: 0009-lvmlockd-fix-sanlock_release-for-vgremove.patch -# RHEL-67039: -Patch10: 0010-raid-count-or-clear-transiently-failed-devices.patch -Patch11: 0011-lvconvert-allow-clearing-superblocks.patch -Patch12: 0012-test-check-raid-superblock-clearing.patch -Patch13: 0013-man-update-raid-man.patch +Patch8: 0008-lvmlockd-fix-missing-free-in-vg_status.patch +Patch9: 0009-lvmlockd-add-repair-option-to-reinitialize-sanlock-l.patch +Patch10: 0010-udev-fix-autoactivation-on-top-of-loop-dev-PVs.patch +Patch11: 0011-lv_manip.c-fix-lvresize-corruption-in-LV-crypt-FS-st.patch +Patch12: 0012-device_id-always-log_error-on-device-ids-write-error.patch +Patch13: 0013-lvmdevices-return-error-if-writing-device-ids-fail-f.patch Patch14: 0014-WHATS_NEW-update.patch +Patch15: 0015-device_id-log_warn-instead-of-log_error-in-device_id.patch +Patch16: 0016-lvmdevices-log_error-when-writing-devices-file-fails.patch +Patch17: 0017-lvmlockd-lockopt-was-mistakenly-ignored-when-nolocki.patch +Patch18: 0018-sanlock-match-lm_lock_sanlock-prototype.patch +Patch19: 0019-lvmlockd-sanlock-fix-struct-pointer-in-release_renam.patch +Patch20: 0020-lvmlockd-free-structs-in-adopt-error-path.patch +Patch21: 0021-lvmlockd-sanlock-check-lock_lv_offset_from_args-resu.patch +Patch22: 0022-lvmlockd-always-free-ls-struct-after-ls-thread-exits.patch +Patch23: 0023-man-lvmlockd-updates.patch +Patch24: 0024-lvmlockd-allow-1-more-extra-character.patch +Patch25: 0025-libdm-stats-fix-type-mismatch-in-bit-operations.patch +Patch26: 0026-cov-prevent-potential-negative-array-index.patch +Patch27: 0027-cov-fix-integer-underflow-in-_count-handling.patch +Patch28: 0028-cov-fix-va_end-resource-leak-in-szscanf.patch +Patch29: 0029-cov-add-explicit-check-for-0-size.patch +Patch30: 0030-cov-explicitly-zero-allocated-mem-for-array.patch +Patch31: 0031-cov-check-for-potential-empty-registry-list.patch +Patch32: 0032-cov-check-for-potential-empty-row-list.patch +Patch33: 0033-gcc-for-C90-don-t-mix-declaration-and-code.patch +Patch34: 0034-sanlock-fix-struct-copy-to-avoid-aliasing-issues.patch +Patch35: 0035-sanlock-fix-file-descriptor-leak-in-error-path.patch +Patch36: 0036-command-lines-fix-typo-in-configurable-name.patch +Patch37: 0037-tools-simplify-LVM_DID_EXEC-environment-variable.patch +Patch38: 0038-gcc-ensure-pointer-is-properly-initialized.patch +Patch39: 0039-dmeventd-check-device-exists.patch +Patch40: 0040-dmeventd-add-device-existence-check.patch +Patch41: 0041-dmeventd-_get_status-returns-success-for-non-monitor.patch +Patch42: 0042-vgsplit-fix-check-for-not-splitting-an-LV-between-tw.patch +Patch43: 0043-vgsplit-fix-check-for-not-splitting-an-LV-between-tw.patch +Patch44: 0044-lvmdevices-do-not-create-system.devices-when-deletin.patch +Patch45: 0045-tools-pvchange-unlock-devices-file-at-the-end-of-cmd.patch +Patch46: 0046-tools-pvchange-unlock-devices-file-at-the-end-of-cmd.patch +Patch47: 0047-make-generate.patch +Patch48: 0048-activating-raid-LV-with-partial-snapshot-is-an-error.patch +Patch49: 0049-lv_manip-show-a-warning-during-classic-snapshot-crea.patch +Patch50: 0050-test-add-new-test-for-snapshot-on-raid-creation-acti.patch +Patch51: 0051-WHATS_NEW-update.patch +# RHEL-135072: +Patch52: 0052-integrity-allow-creating-imeta-with-more-than-one-se.patch +# RHEL-116883: +Patch53: 0053-lvresize-fix-xfs-size-checks.patch +Patch54: 0054-configure-check-for-xfs-header-file.patch +Patch55: 0055-log-add-string.h.patch +Patch56: 0056-filesystem-refactor-code-working-with-xfs.patch +Patch57: 0057-lib-rename-uuid.c-to-id.c.patch +Patch58: 0058-autoreconf-reconfigure.patch BuildRequires: make BuildRequires: gcc @@ -91,6 +135,8 @@ BuildRequires: ncurses-devel BuildRequires: libedit-devel BuildRequires: libaio-devel BuildRequires: libnvme-devel +BuildRequires: xfsprogs-devel +#BuildRequires: libuuid-devel %if %{enable_lockd_dlm} BuildRequires: dlm-devel >= %{dlm_version} %endif @@ -710,6 +756,19 @@ An extensive functional testsuite for LVM2. %endif %changelog +* Thu Jan 15 2026 Marian Csontos - 2.03.33-4 +- Handle wrong XFS reported size when shrinking LV immediately after growing. + +* Tue Jan 06 2026 Marian Csontos - 2.03.33-3 +- Allow integrity to use multiple segments for metadata. + +* Mon Nov 10 2025 Marian Csontos - 2.03.33-2 +- Add message when activating RAID volumes with snapshots. + +* Mon Sep 29 2025 Marian Csontos - 2.03.33-1 +- Update to upstream version 2.03.33. +- See WHATS_NEW and WHATS_NEW_DM for more information. + * Tue Jun 03 2025 Marian Csontos - 2.03.32-2 - Fix vgremove hanging immediately after lockstart. - Add repair option for RAID volumes with too many transiently failed devices.