Update lvm2 to upstream version 2.03.40

Resolves: RHEL-163449
This commit is contained in:
Marian Csontos 2026-04-28 12:19:22 +02:00
parent 8b23f5dd12
commit 4248bd7230
37 changed files with 41 additions and 2491 deletions

View File

@ -1,7 +1,7 @@
From 0802fe7f20de14c5bdb2fc0b3366de52244ec324 Mon Sep 17 00:00:00 2001
From f70692625b359eb8031945f0184aa4ca0216d2b2 Mon Sep 17 00:00:00 2001
From: Marian Csontos <mcsontos@redhat.com>
Date: Fri, 24 Oct 2025 18:34:44 +0200
Subject: [PATCH 01/32] RHEL10
Subject: [PATCH] RHEL10
---
VERSION | 2 +-
@ -9,19 +9,19 @@ Subject: [PATCH 01/32] RHEL10
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/VERSION b/VERSION
index 2f2c0e816..b59be49ca 100644
index 659c9cbe7..1914e5b52 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-2.03.36(2) (2025-10-24)
+2.03.36(2)-RHEL10 (2025-10-24)
-2.03.40(2) (2026-04-28)
+2.03.40(2)-RHEL10 (2026-04-28)
diff --git a/VERSION_DM b/VERSION_DM
index cad6e0219..ec9725808 100644
index 86bbc6cc6..90f4a8cba 100644
--- a/VERSION_DM
+++ b/VERSION_DM
@@ -1 +1 @@
-1.02.210 (2025-10-24)
+1.02.210-RHEL10 (2025-10-24)
-1.02.214 (2026-04-28)
+1.02.214-RHEL10 (2026-04-28)
--
2.52.0
2.54.0

View File

@ -1,62 +0,0 @@
From decf5ca52a522a2cdd93b87762523f22a1a5762d Mon Sep 17 00:00:00 2001
From: Zdenek Kabelac <zkabelac@redhat.com>
Date: Sun, 26 Oct 2025 22:04:03 +0100
Subject: [PATCH 02/32] lvmdbusd: check DEVLINKS when detecting udev events
When a PV is wiped with 'wipefs -a', lvmdbusd needs to detect the
udev change event and refresh its state to remove the wiped PV from
its object database.
The daemon was failing to detect wipefs events because of a device
name mismatch. When a PV is created on a device-mapper device, it
is typically tracked using a path like /dev/mapper/xxx, but the udev
event after wipefs reports DEVNAME as the kernel device name like
/dev/dm-N.
The existing code only checked the DEVNAME property, so it couldn't
find the PV object and never triggered a refresh. This caused the
test_wipefs test case to fail with "Daemon failed to update, missing
udev change event?" after timing out for 5 seconds.
Fix this by also checking the DEVLINKS property when DEVNAME lookup
fails. DEVLINKS contains all symlinks to the device, including the
/dev/mapper path that the daemon uses to track the PV.
This matches how device lookup already works in objectmanager.py,
which uses os.path.realpath() to resolve symlinks when looking up
devices by path.
Co-Authored-By: Claude <noreply@anthropic.com>
(cherry picked from commit 2e46593f74b8118bd97be5d8570e754a3c1a3647)
---
daemons/lvmdbusd/udevwatch.py | 14 +++++++++++++-
1 file changed, 13 insertions(+), 1 deletion(-)
diff --git a/daemons/lvmdbusd/udevwatch.py b/daemons/lvmdbusd/udevwatch.py
index 7ee7c9d1c..2cd03b414 100644
--- a/daemons/lvmdbusd/udevwatch.py
+++ b/daemons/lvmdbusd/udevwatch.py
@@ -74,7 +74,19 @@ def filter_event(action, device):
else:
# This handles the wipefs -a path
if not refresh and 'DEVNAME' in device:
- if cfg.om.get_object_by_lvm_id(device['DEVNAME']):
+ devname = device['DEVNAME']
+ found_obj = cfg.om.get_object_by_lvm_id(devname)
+
+ # Also check device symlinks - udev might report /dev/dm-X but
+ # the PV is tracked under a different name
+ if not found_obj and 'DEVLINKS' in device:
+ devlinks = device['DEVLINKS'].split()
+ for link in devlinks:
+ found_obj = cfg.om.get_object_by_lvm_id(link)
+ if found_obj:
+ break
+
+ if found_obj:
refresh = True
if refresh:
--
2.52.0

View File

@ -1,48 +0,0 @@
From 735f6ae8c2cb52865e32866c3540449db9a3a358 Mon Sep 17 00:00:00 2001
From: David Teigland <teigland@redhat.com>
Date: Mon, 27 Oct 2025 11:01:16 -0500
Subject: [PATCH 03/32] 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 271d453af..b348de78a 100644
--- a/tools/toollib.c
+++ b/tools/toollib.c
@@ -793,6 +793,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.52.0

View File

@ -1,34 +0,0 @@
From 3bc6439874a4a0e17edf44de25d79a0c75f1e98e Mon Sep 17 00:00:00 2001
From: Heinz Mauelshagen <heinzm@redhat.com>
Date: Mon, 27 Oct 2025 17:37:09 +0100
Subject: [PATCH 04/32] 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 f5875cd73..fb2ed53a4 100644
--- a/lib/metadata/lv_manip.c
+++ b/lib/metadata/lv_manip.c
@@ -9765,6 +9765,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.52.0

View File

@ -1,26 +0,0 @@
From 5f376364ffddf84ac83220a856ad627ddef96973 Mon Sep 17 00:00:00 2001
From: Heinz Mauelshagen <heinzm@redhat.com>
Date: Mon, 27 Oct 2025 19:15:06 +0100
Subject: [PATCH 05/32] WHATS_NEW: update
(cherry picked from commit b8f7635e1692fcfc5ea34e1dcaea2ebb6df94431)
---
WHATS_NEW | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/WHATS_NEW b/WHATS_NEW
index 2ca93637d..1841f8db8 100644
--- a/WHATS_NEW
+++ b/WHATS_NEW
@@ -1,3 +1,8 @@
+Version 2.03.37 -
+==================
+ Warn on classic snapshot on raid creation and error on activation + test.
+ Improve lvmdbusd matching of udevd reported device paths.
+
Version 2.03.36 - 24th October 2025
===================================
Fix uninitialized chunk_size_calc_policy in pool parameter functions.
--
2.52.0

View File

@ -1,32 +0,0 @@
From 607a1ec37d58519f3ae015ac5f2cf7b87d4afd70 Mon Sep 17 00:00:00 2001
From: Zdenek Kabelac <zkabelac@redhat.com>
Date: Sat, 1 Nov 2025 22:43:05 +0100
Subject: [PATCH 06/32] cachevol: add missing synchronization with udev
When converting an LV to cachevol, we need to add a synchronization
wait after deactivating the converted and zeroed LV. The same DM
device could be reused for the newly activated volume, and we need
to ensure we do not mix add & remove operations in a single udev
transaction for the same DM device, as that may lead to leaked
symlinks in /dev directory (some udev versions have faulty DB updates).
(cherry picked from commit 17bcac3e353f0a26ef984f068f927332bd06f5a2)
---
lib/metadata/cache_manip.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/lib/metadata/cache_manip.c b/lib/metadata/cache_manip.c
index 06edf0958..7f0adf837 100644
--- a/lib/metadata/cache_manip.c
+++ b/lib/metadata/cache_manip.c
@@ -1298,5 +1298,7 @@ int wipe_cache_pool(struct logical_volume *cache_pool_lv)
r = 0;
}
+ sync_local_dev_names(cache_pool_lv->vg->cmd);
+
return r;
}
--
2.52.0

View File

@ -1,50 +0,0 @@
From 3a410deb0aace9cf02fcb8030acb6a3714f5b6d1 Mon Sep 17 00:00:00 2001
From: Zdenek Kabelac <zkabelac@redhat.com>
Date: Wed, 29 Oct 2025 01:24:11 +0100
Subject: [PATCH 07/32] lvmdbusd: fix deadlock on SIGINT in lvm shell mode
Fix race condition where signal handler could deadlock waiting for
shell_lock while worker thread waits for cfg.run.value to be set.
The deadlock scenario:
1. Worker thread T1 holds shell_lock, waiting in select() (0.5s timeout)
2. Signal handler receives SIGINT, calls exit_shell()
3. exit_shell() blocks trying to acquire shell_lock (held by T1)
4. Signal handler never reaches cfg.run.value = 0 (blocked at step 3)
5. T1 wakes from select(), checks cfg.run.value != 0 (still true!)
6. T1 goes back to select(), repeating until test timeout
Solution: Set cfg.run.value = 0 BEFORE calling exit_shell(). This allows
worker threads to detect shutdown even if the signal handler blocks on
shell_lock, breaking the deadlock.
This fixes occasional test_z_sigint failures in lvm shell mode where the
daemon fails to exit within 10 seconds after receiving SIGINT.
Co-Authored-By: Claude <noreply@anthropic.com>
(cherry picked from commit 31c6ba34f9c6d40f77d716c8c38588796d201189)
---
daemons/lvmdbusd/utils.py | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/daemons/lvmdbusd/utils.py b/daemons/lvmdbusd/utils.py
index 3b1ac801f..7d58f73dd 100644
--- a/daemons/lvmdbusd/utils.py
+++ b/daemons/lvmdbusd/utils.py
@@ -406,10 +406,12 @@ def handler(signum):
cfg.ignore_sigterm = False
return True
+ # Set shutdown flag first so worker threads can detect shutdown
+ # even if exit_shell() blocks on shell_lock
+ cfg.run.value = 0
# If lvm shell is in use, tell it to exit
if cfg.SHELL_IN_USE is not None:
cfg.SHELL_IN_USE.exit_shell()
- cfg.run.value = 0
log_error('Exiting daemon with signal %d' % signum)
if cfg.loop is not None:
cfg.loop.quit()
--
2.52.0

View File

@ -1,30 +0,0 @@
From 8bb78ab1cef5bc61a8b021a74f7021e09fd16d4b Mon Sep 17 00:00:00 2001
From: Zdenek Kabelac <zkabelac@redhat.com>
Date: Mon, 10 Nov 2025 23:10:31 +0100
Subject: [PATCH 08/32] vdo: add missing synchronization
After wiping, formating and deactivating vdopool volume,
we should wait on udev before we continue and activate
same volume again with different UUID.
(cherry picked from commit 6f9c241c81ecbe521d1554d2d603b8e99f88b9d9)
---
lib/metadata/vdo_manip.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/lib/metadata/vdo_manip.c b/lib/metadata/vdo_manip.c
index 735323ce4..13344e423 100644
--- a/lib/metadata/vdo_manip.c
+++ b/lib/metadata/vdo_manip.c
@@ -429,6 +429,8 @@ int convert_vdo_pool_lv(struct logical_volume *data_lv,
return 0;
}
+ sync_local_dev_names(cmd);
+
vdo_logical_size -= 2 * vdo_pool_header_size;
if (vdo_logical_size < extent_size) {
--
2.52.0

View File

@ -1,37 +0,0 @@
From 9f39546dedaa25b061e31e54788553dea2cb0d35 Mon Sep 17 00:00:00 2001
From: Zdenek Kabelac <zkabelac@redhat.com>
Date: Wed, 12 Nov 2025 23:56:00 +0100
Subject: [PATCH 09/32] man: update pvmove for pvmove_max_segment_size_mb
(cherry picked from commit e2cf6050379685f97e8993ac73a404ffaabd0984)
---
man/pvmove.8_end | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/man/pvmove.8_end b/man/pvmove.8_end
index 02f746b4b..7cdb635d9 100644
--- a/man/pvmove.8_end
+++ b/man/pvmove.8_end
@@ -35,6 +35,19 @@ Note that this new process cannot support the original LVM1
type of on-disk metadata. Metadata can be converted using
\fBvgconvert\fP(8).
.P
+By default, pvmove will mirror an entire LV segment at once. If the process
+is interrupted (e.g. by a system crash or power failure) before the segment
+is fully mirrored, the entire segment must be mirrored again when pvmove is
+restarted. For very large segments, this can result in significant rework.
+The \fBallocation/pvmove_max_segment_size_mb\fP setting in \fBlvm.conf\fP(5)
+can be used to limit the maximum size of data mirrored in a single operation.
+When set to a non-zero value, pvmove will split large segments into smaller
+chunks of the specified size (in MiB), mirror each chunk, and update metadata
+between chunks. This ensures that at most one chunk needs to be re-mirrored
+after an interruption. For example, setting this to 10240 will limit each
+mirroring operation to 10 GiB. The default value of 0 means no limit - entire
+segments are mirrored at once.
+.P
If the \fB--atomic\fP option is used, a slightly different approach is
used for the move. Again, a temporary 'pvmove' LV is created to store the
details of all the data movements required. This temporary LV contains
--
2.52.0

View File

@ -1,28 +0,0 @@
From 01bf2b0c664cc9341ce0393ec543401846ffb07f Mon Sep 17 00:00:00 2001
From: Zdenek Kabelac <zkabelac@redhat.com>
Date: Sat, 1 Nov 2025 20:49:49 +0100
Subject: [PATCH 10/32] lvmpersist: typo in PATH
As found in other scripts, cut & paste typo...
(cherry picked from commit 43e32684c082d7e2ac78717d649726daa5bf8fcf)
---
scripts/lvmpersist.sh | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/scripts/lvmpersist.sh b/scripts/lvmpersist.sh
index 02c405425..6af611e07 100755
--- a/scripts/lvmpersist.sh
+++ b/scripts/lvmpersist.sh
@@ -1058,7 +1058,7 @@ usage() {
#
# BEGIN SCRIPT
#
-PATH="/sbin:/usr/sbin:/bin:/usr/sbin:$PATH"
+PATH="/sbin:/usr/sbin:/bin:/usr/bin:$PATH"
SCRIPTNAME=$(basename "$0")
if [ $# -lt 1 ]; then
--
2.52.0

View File

@ -1,44 +0,0 @@
From 7c9f76c763e9ebebf2affa4c3ef4b510a747c520 Mon Sep 17 00:00:00 2001
From: David Teigland <teigland@redhat.com>
Date: Thu, 20 Nov 2025 15:24:50 -0600
Subject: [PATCH 11/32] lvmpersist: remove unregister error message
If PR was already stopped, stopping PR again would
generate an "sg_persist unregiser error" message
when each sg_persist command returned an error.
The actual result of the lvmpersist stop command
is determined by checking that the key is removed,
not by the sg_persist exit code. If the key is not
removed from any device, then the command fails with
another higher level error message.
(cherry picked from commit ea2ab6b7b720fddb445d3adc897df0b41eb9cfcb)
---
scripts/lvmpersist.sh | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/scripts/lvmpersist.sh b/scripts/lvmpersist.sh
index 6af611e07..9cee385ed 100755
--- a/scripts/lvmpersist.sh
+++ b/scripts/lvmpersist.sh
@@ -595,7 +595,7 @@ undo_register() {
else
$cmd $cmdopts --out --register --param-rk="$OURKEY" "$dev" >/dev/null 2>&1
fi
- test $? -eq 0 || logmsg "$cmd unregister error on $dev"
+ # test $? -eq 0 || logmsg "$cmd unregister error on $dev"
done
}
@@ -797,7 +797,7 @@ do_stop() {
$cmd $cmdopts --out --register --param-rk="$OURKEY" "$dev" >/dev/null 2>&1
fi
- test $? -eq 0 || logmsg "$cmd unregister error on $dev"
+ # test $? -eq 0 || logmsg "$cmd unregister error on $dev"
if key_is_on_device "$dev" "$OURKEY" ; then
logmsg "stop $GROUP failed to unregister our key $OURKEY from $dev."
--
2.52.0

View File

@ -1,46 +0,0 @@
From 90b18b3f7694e6ef53387913905e5a357d43ffb6 Mon Sep 17 00:00:00 2001
From: Zdenek Kabelac <zkabelac@redhat.com>
Date: Sat, 25 Oct 2025 22:20:22 +0200
Subject: [PATCH 12/32] man: keep page ascii
Drop utf8 characters. Can be captured with:
$ grep -r -P '[^\x00-\x7f]'
Converted with:
$ iconv -f utf-8 -t ascii//TRANSLIT file > file_ascii
(cherry picked from commit 7a18fc86cedd9b27d636fa9f5857966460f6465a)
---
man/lvmpersist.8_main | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/man/lvmpersist.8_main b/man/lvmpersist.8_main
index e05f25a9e..785e0ed97 100644
--- a/man/lvmpersist.8_main
+++ b/man/lvmpersist.8_main
@@ -71,16 +71,16 @@ Write Exclusive
Exclusive Access
.br
.B WERO
-Write Exclusive registrants only
+Write Exclusive - registrants only
.br
.B EARO
-Exclusive Access registrants only
+Exclusive Access - registrants only
.br
.B WEAR
-Write Exclusive all registrants
+Write Exclusive - all registrants
.br
.B EAAR
-Exclusive Access all registrants
+Exclusive Access - all registrants
.P
(WERO and EARO types are not yet supported.)
.P
--
2.52.0

View File

@ -1,85 +0,0 @@
From cee5f97289d4c775a198f1720e1ed8cfda439851 Mon Sep 17 00:00:00 2001
From: Zdenek Kabelac <zkabelac@redhat.com>
Date: Sat, 25 Oct 2025 22:21:48 +0200
Subject: [PATCH 13/32] man: remove spaces at eol
(cherry picked from commit c96312fe021fd2619eb77638393412d3ab657fb4)
---
man/lvmlockd.8_main | 8 ++++----
man/lvmpersist.8_main | 6 +++---
2 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/man/lvmlockd.8_main b/man/lvmlockd.8_main
index 621224df7..96a033e48 100644
--- a/man/lvmlockd.8_main
+++ b/man/lvmlockd.8_main
@@ -267,7 +267,7 @@ in the last (sixth) attr position for a shared VG:
.
.P
$ vgs
- VG #PV #LV #SN Attr VSize VFree
+ VG #PV #LV #SN Attr VSize VFree
vgfoo 1 0 0 wz--ns 992.00m 736.00m
.fi
.
@@ -279,7 +279,7 @@ reporting field:
.P
.nf
$ vgs -o+shared
- VG #PV #LV #SN Attr VSize VFree Shared
+ VG #PV #LV #SN Attr VSize VFree Shared
vgfoo 1 0 0 wz--ns 992.00m 736.00m shared
.fi
.P
@@ -292,7 +292,7 @@ command can also display the lock type:
.nf
$ vgs -o+locktype
VG #PV #LV #SN Attr VSize VFree LockType
- vgfoo 1 0 0 wz--ns 992.00m 736.00m sanlock
+ vgfoo 1 0 0 wz--ns 992.00m 736.00m sanlock
.fi
.P
.
@@ -306,7 +306,7 @@ option is added:
.P
.nf
$ vgs --shared
- VG #PV #LV #SN Attr VSize VFree
+ VG #PV #LV #SN Attr VSize VFree
vgfoo 1 0 0 wz--ns 992.00m 736.00m
.fi
.
diff --git a/man/lvmpersist.8_main b/man/lvmpersist.8_main
index 785e0ed97..4efc979c0 100644
--- a/man/lvmpersist.8_main
+++ b/man/lvmpersist.8_main
@@ -43,7 +43,7 @@ restart multipathd.)
.SS Persistent reservation types
.P
LVM uses PR type "Write Exclusive" (WE) for devices in a local VG, and
-"Write Exclusive - all registrants" (WEAR) for devices in a shared VG.
+"Write Exclusive - all registrants" (WEAR) for devices in a shared VG.
One exception is dm-multipath devices, for which WEAR is used in both
local and shared VGs (this is needed for all paths to remain usable.)
.P
@@ -54,7 +54,7 @@ The lvmpersist command has two options for specifying the PR type:
Set access to "ex" (exclusive) if the devices should be accessed by only
one host (i.e. the devices are part of a local VG.)
Set access to "sh" (shared) if the devices are meant to be accessed
-concurrently by multiple hosts (i.e. the devices are part of a shared VG.)
+concurrently by multiple hosts (i.e. the devices are part of a shared VG.)
lvmpersist will choose the appropriate PR type for each device (usually
WE for "ex", and WEAR for "sh".)
.TP
@@ -426,7 +426,7 @@ has been started independent of any setpersist settings, then vgremove
will not automatically stop PR on the devices.
.P
.SS vgexport/vgimport
-.B vgexport --persist stop
+.B vgexport --persist stop
stops PR after exporting the VG, and
.B vgimport --persist start
starts PR before importing the VG.
--
2.52.0

View File

@ -1,61 +0,0 @@
From 3c116318f8fe788bfbae9b098d5674cc89c057c4 Mon Sep 17 00:00:00 2001
From: David Teigland <teigland@redhat.com>
Date: Tue, 28 Oct 2025 13:26:59 -0500
Subject: [PATCH 14/32] lvmlockd: vgsplit is not supported
The shared VG restriction was mistakenly removed in
commit 550536474f2b.
(cherry picked from commit accd28140343dc7b507db1bf7047c1d85ab5ec03)
---
man/lvmlockd.8_main | 2 +-
tools/vgsplit.c | 13 +++++++++++++
2 files changed, 14 insertions(+), 1 deletion(-)
diff --git a/man/lvmlockd.8_main b/man/lvmlockd.8_main
index 96a033e48..87cd0b014 100644
--- a/man/lvmlockd.8_main
+++ b/man/lvmlockd.8_main
@@ -838,7 +838,7 @@ splitting mirrors in sanlock VGs
pvmove of entire PVs, or under LVs activated with shared locks
.
.IP \[bu]
-vgmerge
+vgsplit and vgmerge (convert to a local VG to do this)
.
.SS lvmlockd changes from clvmd
.
diff --git a/tools/vgsplit.c b/tools/vgsplit.c
index 8fcfa6ec3..f42b71f10 100644
--- a/tools/vgsplit.c
+++ b/tools/vgsplit.c
@@ -586,6 +586,12 @@ int vgsplit(struct cmd_context *cmd, int argc, char **argv)
return ECMD_FAILED;
}
existing_vg = 1;
+
+ if (vg_is_shared(vg_to)) {
+ log_error("vgsplit is not supported with shared VGs.");
+ unlock_and_release_vg(cmd, vg_to, vg_name_to);
+ return ECMD_FAILED;
+ }
}
if (!(vg_from = vg_read_for_update(cmd, vg_name_from, NULL, 0, 0))) {
@@ -594,6 +600,13 @@ int vgsplit(struct cmd_context *cmd, int argc, char **argv)
return ECMD_FAILED;
}
+ if (vg_is_shared(vg_from)) {
+ log_error("vgsplit is not supported with shared VGs.");
+ unlock_and_release_vg(cmd, vg_to, vg_name_to);
+ unlock_and_release_vg(cmd, vg_from, vg_name_from);
+ return ECMD_FAILED;
+ }
+
cmd->fmt = vg_from->fid->fmt;
if (existing_vg) {
--
2.52.0

View File

@ -1,111 +0,0 @@
From 4bd5b6a09d3004ae64cb2e1187eeda88bd8d63c1 Mon Sep 17 00:00:00 2001
From: David Teigland <teigland@redhat.com>
Date: Wed, 29 Oct 2025 14:57:39 -0500
Subject: [PATCH 15/32] persist: changing lock type should stop PR
Different lock types may use different PR keys, e.g.
sanlock includes a generation number in the PR.
So, stop PR after changing the lock type so it can
be restarted with the new lock type and different key.
(cherry picked from commit cd7c07632bfd738ddfc813dd4ae2db6f480d0e96)
---
lib/device/persist.c | 4 ++--
lib/device/persist.h | 4 ++--
tools/vgchange.c | 11 +++++++++++
tools/vgremove.c | 4 ++--
4 files changed, 17 insertions(+), 6 deletions(-)
diff --git a/lib/device/persist.c b/lib/device/persist.c
index dd4a5bb3a..21ab839d0 100644
--- a/lib/device/persist.c
+++ b/lib/device/persist.c
@@ -1616,7 +1616,7 @@ static int _run_stop(struct cmd_context *cmd, struct volume_group *vg, struct dm
* normal usage pattern, but is still possible.)
*/
-int persist_vgremove_before(struct cmd_context *cmd, struct volume_group *vg, struct dm_list *devs, char **key)
+int persist_finish_before(struct cmd_context *cmd, struct volume_group *vg, struct dm_list *devs, char **key)
{
char *local_key = (char *)find_config_tree_str(cmd, local_pr_key_CFG, NULL);
int local_host_id = find_config_tree_int(cmd, local_host_id_CFG, NULL);
@@ -1674,7 +1674,7 @@ int persist_vgremove_before(struct cmd_context *cmd, struct volume_group *vg, st
return 1;
}
-void persist_vgremove_after(struct cmd_context *cmd, struct volume_group *vg, struct dm_list *devs, char *key)
+void persist_finish_after(struct cmd_context *cmd, struct volume_group *vg, struct dm_list *devs, char *key)
{
if (!_run_stop(cmd, vg, devs, key, 0))
stack;
diff --git a/lib/device/persist.h b/lib/device/persist.h
index ed410e4b6..d94fd1edd 100644
--- a/lib/device/persist.h
+++ b/lib/device/persist.h
@@ -50,8 +50,8 @@ int persist_start(struct cmd_context *cmd, struct volume_group *vg,
int persist_stop(struct cmd_context *cmd, struct volume_group *vg);
-int persist_vgremove_before(struct cmd_context *cmd, struct volume_group *vg, struct dm_list *devs, char **key);
-void persist_vgremove_after(struct cmd_context *cmd, struct volume_group *vg, struct dm_list *devs, char *key);
+int persist_finish_before(struct cmd_context *cmd, struct volume_group *vg, struct dm_list *devs, char **key);
+void persist_finish_after(struct cmd_context *cmd, struct volume_group *vg, struct dm_list *devs, char *key);
int persist_remove(struct cmd_context *cmd, struct volume_group *vg,
char *local_key, int local_host_id, const char *remkey);
diff --git a/tools/vgchange.c b/tools/vgchange.c
index b13ffab7b..eb24597a2 100644
--- a/tools/vgchange.c
+++ b/tools/vgchange.c
@@ -1400,8 +1400,16 @@ static int _vgchange_locktype_single(struct cmd_context *cmd, const char *vg_nam
struct volume_group *vg,
struct processing_handle *handle)
{
+ char *pr_key = NULL;
+ DM_LIST_INIT(pr_devs);
int no_change = 0;
+ /* New lock type may use different PR key, save current key to stop PR below. */
+ if (vg->pr & VG_PR_REQUIRE) {
+ if (!persist_finish_before(cmd, vg, &pr_devs, &pr_key))
+ return_ECMD_FAILED;
+ }
+
if (!_vgchange_locktype(cmd, vg, &no_change))
return_ECMD_FAILED;
@@ -1428,6 +1436,9 @@ static int _vgchange_locktype_single(struct cmd_context *cmd, const char *vg_nam
}
}
+ if (pr_key)
+ persist_finish_after(cmd, vg, &pr_devs, pr_key);
+
log_print_unless_silent("Volume group \"%s\" successfully changed.", vg->name);
return ECMD_PROCESSED;
diff --git a/tools/vgremove.c b/tools/vgremove.c
index 74dfbfb1b..1e45699f5 100644
--- a/tools/vgremove.c
+++ b/tools/vgremove.c
@@ -74,7 +74,7 @@ static int _vgremove_single(struct cmd_context *cmd, const char *vg_name,
!lvremove_single(cmd, vg->pool_metadata_spare_lv, &void_handle))
return_ECMD_FAILED;
- if (pr_stop && !persist_vgremove_before(cmd, vg, &pr_devs, &pr_key))
+ if (pr_stop && !persist_finish_before(cmd, vg, &pr_devs, &pr_key))
return_ECMD_FAILED;
if (!lockd_free_vg_before(cmd, vg, 0, arg_count(cmd, yes_ARG)))
@@ -93,7 +93,7 @@ static int _vgremove_single(struct cmd_context *cmd, const char *vg_name,
lockd_free_vg_final(cmd, vg);
if (pr_stop)
- persist_vgremove_after(cmd, vg, &pr_devs, pr_key);
+ persist_finish_after(cmd, vg, &pr_devs, pr_key);
return ECMD_PROCESSED;
}
--
2.52.0

View File

@ -1,176 +0,0 @@
From 3b513b37d3a5c59ed4d5b6742de7174d56457f50 Mon Sep 17 00:00:00 2001
From: David Teigland <teigland@redhat.com>
Date: Mon, 3 Nov 2025 14:46:06 -0600
Subject: [PATCH 16/32] vgsplit: keep track of the devices that are moved
(cherry picked from commit 1897f4354fc14afefe3611c0626c6e5d2ae3d116)
---
lib/device/dev_util.c | 10 ++++++++++
lib/device/device.h | 1 +
lib/metadata/metadata-exported.h | 5 +++--
lib/metadata/metadata.c | 33 ++++++++++++++++++++++----------
tools/vgsplit.c | 8 ++++++--
5 files changed, 43 insertions(+), 14 deletions(-)
diff --git a/lib/device/dev_util.c b/lib/device/dev_util.c
index 271e8972d..60a10fb4f 100644
--- a/lib/device/dev_util.c
+++ b/lib/device/dev_util.c
@@ -64,3 +64,13 @@ struct device_list *device_list_find_dev(struct dm_list *devices, struct device
return NULL;
}
+int device_list_add(struct dm_pool *mem, struct dm_list *devices, struct device *dev)
+{
+ struct device_list *devl;
+
+ if (!(devl = dm_pool_alloc(mem, sizeof(struct device_list))))
+ return_0;
+ devl->dev = dev;
+ dm_list_add(devices, &devl->list);
+ return 1;
+}
diff --git a/lib/device/device.h b/lib/device/device.h
index 8c3cb53b0..d17d86b93 100644
--- a/lib/device/device.h
+++ b/lib/device/device.h
@@ -250,6 +250,7 @@ int parse_vpd_serial(const unsigned char *in, char *out, size_t outsize);
int device_id_list_remove(struct dm_list *devices, struct device *dev);
struct device_id_list *device_id_list_find_dev(struct dm_list *devices, struct device *dev);
int device_list_remove(struct dm_list *devices, struct device *dev);
+int device_list_add(struct dm_pool *mem, struct dm_list *devices, struct device *dev);
struct device_list *device_list_find_dev(struct dm_list *devices, struct device *dev);
char *strdup_pvid(char *pvid);
diff --git a/lib/metadata/metadata-exported.h b/lib/metadata/metadata-exported.h
index ed3e49289..29e7ba99f 100644
--- a/lib/metadata/metadata-exported.h
+++ b/lib/metadata/metadata-exported.h
@@ -731,10 +731,11 @@ void lv_set_hidden(struct logical_volume *lv);
int pv_write(struct cmd_context *cmd, struct physical_volume *pv, int allow_non_orphan);
int move_pv(struct volume_group *vg_from, struct volume_group *vg_to,
- const char *pv_name);
+ const char *pv_name, struct device **dev_moved);
int move_pvs_used_by_lv(struct volume_group *vg_from,
struct volume_group *vg_to,
- const char *lv_name);
+ const char *lv_name,
+ struct dm_list *dev_list_moved);
int is_orphan_vg(const char *vg_name);
int is_real_vg(const char *vg_name);
int vg_missing_pv_count(const struct volume_group *vg);
diff --git a/lib/metadata/metadata.c b/lib/metadata/metadata.c
index 67ade62aa..06bbc5702 100644
--- a/lib/metadata/metadata.c
+++ b/lib/metadata/metadata.c
@@ -430,11 +430,14 @@ int add_pv_to_vg(struct volume_group *vg, const char *pv_name,
}
static int _move_pv(struct volume_group *vg_from, struct volume_group *vg_to,
- const char *pv_name, int enforce_pv_from_source)
+ const char *pv_name, int enforce_pv_from_source,
+ struct device **dev_moved)
{
struct physical_volume *pv;
struct pv_list *pvl;
+ *dev_moved = NULL;
+
/* FIXME: handle tags */
if (!(pvl = find_pv_in_vg(vg_from, pv_name))) {
if (!enforce_pv_from_source &&
@@ -466,41 +469,51 @@ static int _move_pv(struct volume_group *vg_from, struct volume_group *vg_to,
vg_from->free_count -= pv_pe_count(pv) - pv_pe_alloc_count(pv);
vg_to->free_count += pv_pe_count(pv) - pv_pe_alloc_count(pv);
+ *dev_moved = pv->dev;
+
return 1;
}
int move_pv(struct volume_group *vg_from, struct volume_group *vg_to,
- const char *pv_name)
+ const char *pv_name, struct device **dev_moved)
{
- return _move_pv(vg_from, vg_to, pv_name, 1);
+ return _move_pv(vg_from, vg_to, pv_name, 1, dev_moved);
}
struct vg_from_to {
struct volume_group *from;
struct volume_group *to;
+ struct dm_list *dev_list;
};
static int _move_pvs_used_by_lv_cb(struct logical_volume *lv, void *data)
{
struct vg_from_to *v = (struct vg_from_to*) data;
struct lv_segment *lvseg;
+ struct dm_list *dev_list = v->dev_list;
+ struct device *dev_moved;
unsigned s;
- dm_list_iterate_items(lvseg, &lv->segments)
- for (s = 0; s < lvseg->area_count; s++)
- if (seg_type(lvseg, s) == AREA_PV)
- if (!_move_pv(v->from, v->to,
- pv_dev_name(seg_pv(lvseg, s)), 0))
+ dm_list_iterate_items(lvseg, &lv->segments) {
+ for (s = 0; s < lvseg->area_count; s++) {
+ if (seg_type(lvseg, s) == AREA_PV) {
+ if (!_move_pv(v->from, v->to, pv_dev_name(seg_pv(lvseg, s)), 0, &dev_moved))
return_0;
+ if (dev_list && dev_moved && !device_list_add(lv->vg->cmd->mem, dev_list, dev_moved))
+ return_0;
+ }
+ }
+ }
return 1;
}
int move_pvs_used_by_lv(struct volume_group *vg_from,
struct volume_group *vg_to,
- const char *lv_name)
+ const char *lv_name,
+ struct dm_list *dev_list)
{
- struct vg_from_to data = { .from = vg_from, .to = vg_to };
+ struct vg_from_to data = { .from = vg_from, .to = vg_to, .dev_list = dev_list };
struct lv_list *lvl;
/* FIXME: handle tags */
diff --git a/tools/vgsplit.c b/tools/vgsplit.c
index f42b71f10..2d93c1935 100644
--- a/tools/vgsplit.c
+++ b/tools/vgsplit.c
@@ -523,6 +523,8 @@ int vgsplit(struct cmd_context *cmd, int argc, char **argv)
struct vgcreate_params vp_def;
const char *vg_name_from, *vg_name_to;
struct volume_group *vg_to, *vg_from = NULL;
+ DM_LIST_INIT(devs_moved);
+ struct device *dev_moved;
int opt;
int existing_vg = 0;
int r = ECMD_FAILED;
@@ -648,12 +650,14 @@ int vgsplit(struct cmd_context *cmd, int argc, char **argv)
/* Move PVs across to new structure */
for (opt = 0; opt < argc; opt++) {
dm_unescape_colons_and_at_signs(argv[opt], NULL, NULL);
- if (!move_pv(vg_from, vg_to, argv[opt]))
+ if (!move_pv(vg_from, vg_to, argv[opt], &dev_moved))
+ goto_bad;
+ if (dev_moved && !device_list_add(cmd->mem, &devs_moved, dev_moved))
goto_bad;
}
/* If an LV given on the cmdline, move used_by PVs */
- if (lv_name && !move_pvs_used_by_lv(vg_from, vg_to, lv_name))
+ if (lv_name && !move_pvs_used_by_lv(vg_from, vg_to, lv_name, &devs_moved))
goto_bad;
/*
--
2.52.0

View File

@ -1,113 +0,0 @@
From 133005d4560b5066d9150d616bfbb8e4d80f17a6 Mon Sep 17 00:00:00 2001
From: David Teigland <teigland@redhat.com>
Date: Mon, 3 Nov 2025 15:44:13 -0600
Subject: [PATCH 17/32] vgsplit: update PR on devs to match destination VG
Stop or start PR on PVs being moved to match the PR
settings of the destination VG.
(cherry picked from commit 987aab1e26e129e2969a30aaa0c475a395a55b22)
---
lib/device/persist.c | 22 ++++++++++++++++++++++
lib/device/persist.h | 1 +
tools/vgsplit.c | 18 ++++++++++++++++++
3 files changed, 41 insertions(+)
diff --git a/lib/device/persist.c b/lib/device/persist.c
index 21ab839d0..2b22c8f0a 100644
--- a/lib/device/persist.c
+++ b/lib/device/persist.c
@@ -1682,6 +1682,28 @@ void persist_finish_after(struct cmd_context *cmd, struct volume_group *vg, stru
persist_key_file_remove(cmd, vg);
}
+int persist_stop_devs(struct cmd_context *cmd, struct volume_group *vg, struct dm_list *stop_devs)
+{
+ char *local_key = (char *)find_config_tree_str(cmd, local_pr_key_CFG, NULL);
+ int local_host_id = find_config_tree_int(cmd, local_host_id_CFG, NULL);
+ char our_key_buf[PR_KEY_BUF_SIZE] = { 0 };
+ uint64_t our_key_val = 0;
+
+ if (vg_is_sanlock(vg))
+ local_key = NULL;
+
+ if (!local_key && !local_host_id)
+ return 1;
+
+ if (!get_our_key(cmd, vg, local_key, local_host_id, our_key_buf, &our_key_val))
+ return_0;
+
+ if (!_run_stop(cmd, vg, stop_devs, our_key_buf, 0))
+ return_0;
+
+ return 1;
+}
+
int persist_stop(struct cmd_context *cmd, struct volume_group *vg)
{
DM_LIST_INIT(devs);
diff --git a/lib/device/persist.h b/lib/device/persist.h
index d94fd1edd..3792ee580 100644
--- a/lib/device/persist.h
+++ b/lib/device/persist.h
@@ -49,6 +49,7 @@ int persist_start(struct cmd_context *cmd, struct volume_group *vg,
const char *update_our_key);
int persist_stop(struct cmd_context *cmd, struct volume_group *vg);
+int persist_stop_devs(struct cmd_context *cmd, struct volume_group *vg, struct dm_list *stop_devs);
int persist_finish_before(struct cmd_context *cmd, struct volume_group *vg, struct dm_list *devs, char **key);
void persist_finish_after(struct cmd_context *cmd, struct volume_group *vg, struct dm_list *devs, char *key);
diff --git a/tools/vgsplit.c b/tools/vgsplit.c
index 2d93c1935..8397d4176 100644
--- a/tools/vgsplit.c
+++ b/tools/vgsplit.c
@@ -14,6 +14,7 @@
*/
#include "tools.h"
+#include "lib/device/persist.h"
static int _lv_is_in_vg(struct volume_group *vg, struct logical_volume *lv)
{
@@ -525,6 +526,7 @@ int vgsplit(struct cmd_context *cmd, int argc, char **argv)
struct volume_group *vg_to, *vg_from = NULL;
DM_LIST_INIT(devs_moved);
struct device *dev_moved;
+ int pr_from, pr_to;
int opt;
int existing_vg = 0;
int r = ECMD_FAILED;
@@ -711,6 +713,19 @@ int vgsplit(struct cmd_context *cmd, int argc, char **argv)
/* store it on disks */
log_verbose("Writing out updated volume groups");
+ /*
+ * Make PR of moved PVs match the VG they are moved to.
+ * !pr_from && pr_to: on dest, not on source: start dest PR before move
+ * pr_from && !pr_to: on source, not on dest: stop dest PR after move
+ */
+ pr_from = (vg_from->pr & (VG_PR_REQUIRE|VG_PR_AUTOSTART)) ? 1 : 0;
+ pr_to = (vg_to->pr & (VG_PR_REQUIRE|VG_PR_AUTOSTART)) ? 1 : 0;
+
+ if (!pr_from && pr_to && !persist_start(cmd, vg_to,
+ (char *)find_config_tree_str(cmd, local_pr_key_CFG, NULL),
+ find_config_tree_int(cmd, local_host_id_CFG, NULL), NULL, NULL))
+ goto_bad;
+
/*
* First, write out the new VG as EXPORTED. We do this first in case
* there is a crash - we will still have the new VG information, in an
@@ -755,6 +770,9 @@ int vgsplit(struct cmd_context *cmd, int argc, char **argv)
backup(vg_to);
+ if (pr_from && !pr_to && !persist_stop_devs(cmd, vg_to, &devs_moved))
+ log_warn("WARNING: Failed to stop PR.");
+
log_print_unless_silent("%s volume group \"%s\" successfully split from \"%s\"",
existing_vg ? "Existing" : "New",
vg_to->name, vg_from->name);
--
2.52.0

View File

@ -1,31 +0,0 @@
From 804931949482cbf7b0bbdaae31beefeb0a5eed12 Mon Sep 17 00:00:00 2001
From: David Teigland <teigland@redhat.com>
Date: Tue, 4 Nov 2025 10:37:43 -0600
Subject: [PATCH 18/32] vgmerge: require VGs to have the same PR settings
(cherry picked from commit 2a9a1f01d1b48f97008d9e858dbc3f6b052f76d9)
---
tools/vgmerge.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/tools/vgmerge.c b/tools/vgmerge.c
index 710dfef35..29a4b8577 100644
--- a/tools/vgmerge.c
+++ b/tools/vgmerge.c
@@ -109,6 +109,13 @@ static int _vgmerge_single(struct cmd_context *cmd, const char *vg_name_to,
return_ECMD_FAILED;
}
+ if (vg_from->pr != vg_to->pr) {
+ log_error("VGs must have the same PR settings to merge.");
+ unlock_and_release_vg(cmd, vg_from, vg_name_from);
+ unlock_and_release_vg(cmd, vg_to, vg_name_to);
+ return ECMD_FAILED;
+ }
+
if (!vgs_are_compatible(cmd, vg_from, vg_to))
goto_bad;
--
2.52.0

View File

@ -1,40 +0,0 @@
From 04910bbfe2cd86d79221cafc92692da2716b2611 Mon Sep 17 00:00:00 2001
From: David Teigland <teigland@redhat.com>
Date: Tue, 4 Nov 2025 11:26:14 -0600
Subject: [PATCH 19/32] vgimportclone: don't use PR on device being imported
The PR ability/settings in the VG metadata applied to the original
device, but may not apply to the device that the VG metadata was
copied to, so don't use PR on the new device.
(cherry picked from commit c965aa5f4e5dc324ac0c07d5961e4f82563ff325)
---
tools/vgimportclone.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/tools/vgimportclone.c b/tools/vgimportclone.c
index 19e5166f5..12b830724 100644
--- a/tools/vgimportclone.c
+++ b/tools/vgimportclone.c
@@ -117,6 +117,9 @@ static int _update_vg(struct cmd_context *cmd, struct volume_group *vg,
vg->lock_args = NULL;
vg->system_id = cmd->system_id ? dm_pool_strdup(vg->vgmem, cmd->system_id) : NULL;
+ /* The PR ability/settings of the orginal dev may not work on the cloned dev. */
+ vg->pr = 0;
+
dm_list_iterate_items(pvl, &vg->pvs) {
if (!(new_pvl = dm_pool_zalloc(vg->vgmem, sizeof(*new_pvl))))
goto_bad;
@@ -224,6 +227,8 @@ int vgimportclone(struct cmd_context *cmd, int argc, char **argv)
vp.import_devices = arg_is_set(cmd, importdevices_ARG);
vp.import_vg = arg_is_set(cmd, import_ARG);
+ cmd->disable_pr_required = 1;
+
if (!lock_global(cmd, "ex"))
return ECMD_FAILED;
--
2.52.0

View File

@ -1,80 +0,0 @@
From 5f0a602d4e37a536ff17566e2ef4d422ce6a3976 Mon Sep 17 00:00:00 2001
From: David Teigland <teigland@redhat.com>
Date: Tue, 21 Oct 2025 14:56:13 -0500
Subject: [PATCH 20/32] vgs: add reporting field pr
vgs -o pr
shows persistent reservation status, e.g. stopped or started.
(cherry picked from commit 257ba9b97e671c206b069330d9b44e4697b7f724)
---
lib/report/columns.h | 3 ++-
lib/report/properties.c | 2 ++
lib/report/report.c | 17 +++++++++++++++++
3 files changed, 21 insertions(+), 1 deletion(-)
diff --git a/lib/report/columns.h b/lib/report/columns.h
index 7dbe14515..22c784171 100644
--- a/lib/report/columns.h
+++ b/lib/report/columns.h
@@ -237,7 +237,8 @@ FIELD(VGS, vg, STR, "SYS ID", cmd, 0, vgsystemid, vg_sysid, "System ID of the VG
FIELD(VGS, vg, STR, "System ID", cmd, 0, vgsystemid, vg_systemid, "System ID of the VG indicating which host owns it.", 0)
FIELD(VGS, vg, STR, "LockType", cmd, 0, vglocktype, vg_lock_type, "Lock type of the VG used by lvmlockd.", 0)
FIELD(VGS, vg, STR, "VLockArgs", cmd, 0, vglockargs, vg_lock_args, "Lock args of the VG used by lvmlockd.", 0)
-FIELD(VGS, vg, STR, "PR", cmd, 0, vgpersist, vg_persist, "Persistent Reservation.", 0)
+FIELD(VGS, vg, STR, "PRSet", cmd, 0, vgpersist, vg_persist, "Persistent Reservation setting.", 0)
+FIELD(VGS, vg, STR, "PR", cmd, 0, vgprstatus, vg_pr, "Persistent Reservation status.", 0)
FIELD(VGS, vg, SIZ, "Ext", extent_size, 0, size32, vg_extent_size, "Size of Physical Extents in current units.", 0)
FIELD(VGS, vg, NUM, "#Ext", extent_count, 0, uint32, vg_extent_count, "Total number of Physical Extents.", 0)
FIELD(VGS, vg, NUM, "Free", free_count, 0, uint32, vg_free_count, "Total number of unallocated Physical Extents.", 0)
diff --git a/lib/report/properties.c b/lib/report/properties.c
index 46ea8dd2e..27139646c 100644
--- a/lib/report/properties.c
+++ b/lib/report/properties.c
@@ -548,6 +548,8 @@ GET_VG_STR_PROPERTY_FN(vg_lock_args, vg_lock_args_dup(vg))
#define _vg_lock_args_set prop_not_implemented_set
#define _vg_persist_set prop_not_implemented_set
#define _vg_persist_get prop_not_implemented_get
+#define _vg_pr_set prop_not_implemented_set
+#define _vg_pr_get prop_not_implemented_get
GET_VG_NUM_PROPERTY_FN(vg_extent_size, (SECTOR_SIZE * vg->extent_size))
#define _vg_extent_size_set prop_not_implemented_set
GET_VG_NUM_PROPERTY_FN(vg_extent_count, vg->extent_count)
diff --git a/lib/report/report.c b/lib/report/report.c
index 5237aedd9..be32e1bb0 100644
--- a/lib/report/report.c
+++ b/lib/report/report.c
@@ -24,6 +24,7 @@
#include "lib/cache/lvmcache.h"
#include "lib/device/device-types.h"
#include "lib/device/device_id.h"
+#include "lib/device/persist.h"
#include "lib/datastruct/str_list.h"
#include "lib/locking/lvmlockd.h"
@@ -3018,6 +3019,22 @@ static int _vgpersist_disp(struct dm_report *rh, struct dm_pool *mem,
return _field_string(rh, field, "");
}
+static int _vgprstatus_disp(struct dm_report *rh, struct dm_pool *mem,
+ struct dm_report_field *field,
+ const void *data, void *private)
+{
+ struct volume_group *vg = (struct volume_group *) data;
+ struct cmd_context *cmd = (struct cmd_context *) private;
+
+ if (!vg->pr)
+ return _field_string(rh, field, "");
+
+ if (persist_is_started(cmd, vg, 1))
+ return _field_string(rh, field, "started");
+ else
+ return _field_string(rh, field, "stopped");
+}
+
static int _lvuuid_disp(struct dm_report *rh __attribute__((unused)), struct dm_pool *mem,
struct dm_report_field *field,
const void *data, void *private __attribute__((unused)))
--
2.52.0

View File

@ -1,31 +0,0 @@
From b43651bdbc50e4d3f4837d040dd8e943b98277eb Mon Sep 17 00:00:00 2001
From: David Teigland <teigland@redhat.com>
Date: Thu, 13 Nov 2025 13:55:08 -0600
Subject: [PATCH 21/32] vgchange: limit persist stop in lockstop
"vgchange --lockstop --persist stop" should skip the
persist_stop() on a VG without PR required, otherwise
it hits errors attempting to stop PR on VGs where it's
not used.
(cherry picked from commit 4b9cd637d6b23c599f987f44c86035260ee21f2c)
---
tools/vgchange.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tools/vgchange.c b/tools/vgchange.c
index eb24597a2..b701bc54a 100644
--- a/tools/vgchange.c
+++ b/tools/vgchange.c
@@ -736,7 +736,7 @@ static int _vgchange_lock_stop(struct cmd_context *cmd, struct volume_group *vg)
return_0;
/* stop is the only --persist value that's accepted */
- if (arg_is_set(cmd, persist_ARG) && !persist_stop(cmd, vg))
+ if (arg_is_set(cmd, persist_ARG) && (vg->pr & VG_PR_REQUIRE) && !persist_stop(cmd, vg))
log_warn("WARNING: PR stop failed, see lvmpersist stop.");
return 1;
--
2.52.0

View File

@ -1,111 +0,0 @@
From a7747ecf1ebcda1630f3ef5ee223125a2cae656f Mon Sep 17 00:00:00 2001
From: David Teigland <teigland@redhat.com>
Date: Thu, 6 Nov 2025 16:45:28 -0600
Subject: [PATCH 22/32] device_id: prevent incorrect dm uuid idtype
If a dm-uuid-based device was added to system.devices, and
the wrong dm-based type was specified, then the system.devices
entry would have the correct idname but the wrong idtype. e.g.
lvmdevices --adddev /dev/mapper/mpatha --deviceidtype crypt_uuid
would add an entry with: IDTYPE=crypt_uuid IDNAME=mpath-<uuid>
rather than the correct: IDTYPE=mpath_uuid IDNAME=mpath-<uuid>
This mistaken type would not affect lvm, and the device would
be entirely usable. The dm-based types (mpath, crypt, lvmlv)
were interchangable because they all read the device id from
the same dm/uuid sysfs file.
Fix this by adding a missing check that the dm uuid prefix is
correct for the specified idtype. Also, accept an existing
system.devices file which contains this mistake.
(cherry picked from commit f0b991a9ef9b0e232cf38df44693a1b935ed93d3)
---
lib/device/device_id.c | 54 +++++++++++++++++++++++++++++++++++++++++-
1 file changed, 53 insertions(+), 1 deletion(-)
diff --git a/lib/device/device_id.c b/lib/device/device_id.c
index 24a957795..c989187e2 100644
--- a/lib/device/device_id.c
+++ b/lib/device/device_id.c
@@ -823,9 +823,22 @@ char *device_id_system_read(struct cmd_context *cmd, struct device *dev, uint16_
_dev_read_sys_serial(cmd, dev, sysbuf, sizeof(sysbuf));
break;
case DEV_ID_TYPE_MPATH_UUID:
+ if (!dev_dm_uuid(cmd, dev, sysbuf, sizeof(sysbuf)))
+ stack;
+ if (sysbuf[0] && !dm_uuid_has_prefix(sysbuf, "mpath-"))
+ sysbuf[0] = '\0';
+ break;
case DEV_ID_TYPE_CRYPT_UUID:
+ if (!dev_dm_uuid(cmd, dev, sysbuf, sizeof(sysbuf)))
+ stack;
+ if (sysbuf[0] && !dm_uuid_has_prefix(sysbuf, "CRYPT-"))
+ sysbuf[0] = '\0';
+ break;
case DEV_ID_TYPE_LVMLV_UUID:
- (void)dev_dm_uuid(cmd, dev, sysbuf, sizeof(sysbuf));
+ if (!dev_dm_uuid(cmd, dev, sysbuf, sizeof(sysbuf)))
+ stack;
+ if (sysbuf[0] && !dm_uuid_has_prefix(sysbuf, "LVM-"))
+ sysbuf[0] = '\0';
break;
case DEV_ID_TYPE_MD_UUID:
read_sys_block(cmd, dev, "md/uuid", sysbuf, sizeof(sysbuf));
@@ -2503,6 +2516,33 @@ static int _match_dm_names(struct cmd_context *cmd, char *idname, struct device
return 0;
}
+static void _replace_incorrect_dm_idtype(struct dev_use *du)
+{
+ /* Previous bug let one of these types be swapped for another
+ because they all read their value from sysfs file dm/uuid. */
+ if (du->idtype != DEV_ID_TYPE_MPATH_UUID &&
+ du->idtype != DEV_ID_TYPE_CRYPT_UUID &&
+ du->idtype != DEV_ID_TYPE_LVMLV_UUID)
+ return;
+
+ /* Use the IDNAME value to determine the correct IDTYPE. */
+ if (dm_uuid_has_prefix(du->idname, "mpath-") && (du->idtype != DEV_ID_TYPE_MPATH_UUID)) {
+ log_debug("replace incorrect mpath device id type for %u %s", du->idtype, du->idname);
+ du->idtype = DEV_ID_TYPE_MPATH_UUID;
+ return;
+ }
+ if (dm_uuid_has_prefix(du->idname, "CRYPT-") && (du->idtype != DEV_ID_TYPE_CRYPT_UUID)) {
+ log_debug("replace incorrect crypt device id type for %u %s", du->idtype, du->idname);
+ du->idtype = DEV_ID_TYPE_CRYPT_UUID;
+ return;
+ }
+ if (dm_uuid_has_prefix(du->idname, "LVM-") && (du->idtype != DEV_ID_TYPE_LVMLV_UUID)) {
+ log_debug("replace incorrect lvmlv device id type for %u %s", du->idtype, du->idname);
+ du->idtype = DEV_ID_TYPE_LVMLV_UUID;
+ return;
+ }
+}
+
/*
* du is a devices file entry. dev is any device on the system.
* check if du is for dev by comparing the device's ids to du->idname.
@@ -2613,6 +2653,18 @@ static int _match_du_to_dev(struct cmd_context *cmd, struct dev_use *du, struct
_reduce_repeating_underscores(du_idname, sizeof(du_idname));
}
+ /*
+ * A past bug allowed mpath, crypt, or lvm devices to be added to
+ * system.devices using any of the dm id types, and they could be
+ * used normally. Accept an old system.devices with that mistake
+ * by updating du->idtype to have the correct idtype based on the
+ * idname dm prefix.
+ */
+ if (((du->idtype == DEV_ID_TYPE_MPATH_UUID) && !dm_uuid_has_prefix(du->idname, "mpath-")) ||
+ ((du->idtype == DEV_ID_TYPE_CRYPT_UUID) && !dm_uuid_has_prefix(du->idname, "CRYPT-")) ||
+ ((du->idtype == DEV_ID_TYPE_LVMLV_UUID) && !dm_uuid_has_prefix(du->idname, "LVM")))
+ _replace_incorrect_dm_idtype(du);
+
/*
* Try to match du with ids that have already been read for the dev
* (and saved on dev->ids to avoid rereading.)
--
2.52.0

View File

@ -1,84 +0,0 @@
From 70c87a5623825c47908b80d14915b33d6f32f6b2 Mon Sep 17 00:00:00 2001
From: Zdenek Kabelac <zkabelac@redhat.com>
Date: Mon, 15 Dec 2025 22:13:12 +0100
Subject: [PATCH 23/32] cache: adding sync points
(cherry picked from commit 1eec0a1b6bc06fa6733c5de3875d0bd03880927f)
---
lib/metadata/cache_manip.c | 18 +++++++++++-------
lib/metadata/writecache_manip.c | 3 ++-
2 files changed, 13 insertions(+), 8 deletions(-)
diff --git a/lib/metadata/cache_manip.c b/lib/metadata/cache_manip.c
index 7f0adf837..6a02964a7 100644
--- a/lib/metadata/cache_manip.c
+++ b/lib/metadata/cache_manip.c
@@ -555,6 +555,7 @@ int lv_cache_wait_for_clean(struct logical_volume *cache_lv, int *is_clean)
*/
int lv_cache_remove(struct logical_volume *cache_lv)
{
+ struct cmd_context *cmd = cache_lv->vg->cmd;
struct lv_segment *cache_seg = first_seg(cache_lv);
struct logical_volume *corigin_lv;
struct logical_volume *cache_pool_lv;
@@ -562,7 +563,7 @@ int lv_cache_remove(struct logical_volume *cache_lv)
uint64_t data_len, metadata_len;
cache_mode_t cache_mode;
int temp_activated = 0;
- int is_clear;
+ int r, is_clear;
if (!lv_is_cache(cache_lv)) {
log_error(INTERNAL_ERROR "LV %s is not cache volume.",
@@ -625,14 +626,16 @@ int lv_cache_remove(struct logical_volume *cache_lv)
* remove the cache_pool then without waiting for the flush to
* complete.
*/
- if (!lv_cache_wait_for_clean(cache_lv, &is_clear)) {
- if (temp_activated && !deactivate_lv(cache_lv->vg->cmd, cache_lv))
- stack;
- return_0;
+ r = lv_cache_wait_for_clean(cache_lv, &is_clear);
+ if (temp_activated) {
+ sync_local_dev_names(cmd);
+ if (!deactivate_lv(cmd, cache_lv))
+ log_warn("Failed to deactivate after cleaning cache.");
+ sync_local_dev_names(cmd);
}
- if (temp_activated && !deactivate_lv(cache_lv->vg->cmd, cache_lv))
- log_warn("Failed to deactivate after cleaning cache.");
+ if (!r)
+ return_0;
cache_pool_lv = cache_seg->pool_lv;
if (!detach_pool_lv(cache_seg))
@@ -697,6 +700,7 @@ int lv_cache_remove(struct logical_volume *cache_lv)
if (!lv_update_and_reload(cache_lv))
return_0;
cache_lv = corigin_lv;
+ sync_local_dev_names(cmd);
remove:
if (!detach_pool_lv(cache_seg))
return_0;
diff --git a/lib/metadata/writecache_manip.c b/lib/metadata/writecache_manip.c
index ab7fc2c8c..8c8caa6cb 100644
--- a/lib/metadata/writecache_manip.c
+++ b/lib/metadata/writecache_manip.c
@@ -376,6 +376,8 @@ static int _lv_detach_writecache_cachevol_active(struct logical_volume *lv, int
return 0;
}
+ sync_local_dev_names(cmd);
+
log_debug("Deactivating previous cachevol %s", display_lvname(lv_fast));
if (!deactivate_lv(cmd, lv_fast))
@@ -506,4 +508,3 @@ int writecache_settings_to_str_list(struct writecache_settings *settings, struct
return 1;
}
-
--
2.52.0

View File

@ -1,44 +0,0 @@
From fe0326283e7d6fb2171e316440b8a632f93c3545 Mon Sep 17 00:00:00 2001
From: David Teigland <teigland@redhat.com>
Date: Thu, 6 Nov 2025 19:28:25 -0600
Subject: [PATCH 24/32] lvmdevices: update force option
When lvmdevices --update doesn't see any reason to update
system.devices, it doesn't update. Let the user force an
update in case they see a reason to do it.
(cherry picked from commit c65ec4ebc66ae1fc57cd750fa45ff1aea0014457)
---
tools/command-lines.in | 2 +-
tools/lvmdevices.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/tools/command-lines.in b/tools/command-lines.in
index 778187e44..f599a440c 100644
--- a/tools/command-lines.in
+++ b/tools/command-lines.in
@@ -1477,7 +1477,7 @@ OO: --refresh
DESC: Check the devices file and report incorrect values.
lvmdevices --update
-OO: --delnotfound, --refresh
+OO: --delnotfound, --refresh, --force
ID: lvmdevices_update
DESC: Update the devices file to fix incorrect values.
diff --git a/tools/lvmdevices.c b/tools/lvmdevices.c
index 54e33d00c..647098662 100644
--- a/tools/lvmdevices.c
+++ b/tools/lvmdevices.c
@@ -756,7 +756,7 @@ 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 (update_needed || !dm_list_empty(&found_devs) || cmd->devices_file_hash_mismatch || arg_is_set(cmd, force_ARG)) {
if (!device_ids_write(cmd)) {
log_error(failed_to_write_devices_file_msg);
goto_bad;
--
2.52.0

View File

@ -1,350 +0,0 @@
From 60bd34f01ed4c708fc40421a71a44313c85d8afc Mon Sep 17 00:00:00 2001
From: David Teigland <teigland@redhat.com>
Date: Thu, 11 Dec 2025 14:48:42 -0600
Subject: [PATCH 25/32] 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 45895b87b..1e92bae52 100644
--- a/lib/device/filesystem.c
+++ b/lib/device/filesystem.c
@@ -22,7 +22,21 @@
#include <dirent.h>
#include <mntent.h>
+#include <uuid/uuid.h>
#include <sys/ioctl.h>
+#include <linux/types.h>
+/* including xfs/linux.h causes uuid_t conflicts, so define some types that are needed */
+/* #include <xfs/linux.h> */
+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 <xfs/xfs_types.h>
+#ifndef __user
+#define __user
+#endif
+#include <xfs/xfs_fs.h>
static const char *_get_lvresize_fs_helper_path(struct cmd_context *cmd)
{
@@ -251,8 +265,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 };
@@ -338,14 +380,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 fb2ed53a4..0ef3a8991 100644
--- a/lib/metadata/lv_manip.c
+++ b/lib/metadata/lv_manip.c
@@ -6472,7 +6472,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) {
@@ -6591,7 +6591,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)) {
@@ -6613,7 +6613,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 a76eda099..c601267f0 100644
--- a/test/shell/lvresize-fs-crypt.sh
+++ b/test/shell/lvresize-fs-crypt.sh
@@ -107,6 +107,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 153304962..e54790f19 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 6fe467950..91374a10a 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"
@@ -254,6 +254,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

View File

@ -1,37 +0,0 @@
From eb21ff54f065609e76d83db3bf43647f3dae4240 Mon Sep 17 00:00:00 2001
From: Zdenek Kabelac <zkabelac@redhat.com>
Date: Sun, 14 Dec 2025 17:15:37 +0100
Subject: [PATCH 26/32] 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 d64a40759..9a0228a2e 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)])],
@@ -2129,6 +2130,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

View File

@ -1,208 +0,0 @@
From 94bf136e278a12300a2bf5c5688030c172584dc0 Mon Sep 17 00:00:00 2001
From: Zdenek Kabelac <zkabelac@redhat.com>
Date: Sun, 14 Dec 2025 17:14:08 +0100
Subject: [PATCH 27/32] 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 23a0be885..f460ce592 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 1e92bae52..d66536e1a 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 <dirent.h>
#include <mntent.h>
-#include <uuid/uuid.h>
#include <sys/ioctl.h>
#include <linux/types.h>
-/* including xfs/linux.h causes uuid_t conflicts, so define some types that are needed */
-/* #include <xfs/linux.h> */
-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 <xfs/xfs_types.h>
-#ifndef __user
-#define __user
-#endif
-#include <xfs/xfs_fs.h>
static const char *_get_lvresize_fs_helper_path(struct cmd_context *cmd)
{
@@ -265,34 +253,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)
{
@@ -386,8 +346,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 <linux/limits.h> /* 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 <xfs/xfs.h>
+
+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

View File

@ -1,82 +0,0 @@
From c0197f7c74ac94a5707db598d7445ad68a1bf31b Mon Sep 17 00:00:00 2001
From: Zdenek Kabelac <zkabelac@redhat.com>
Date: Mon, 15 Dec 2025 11:44:40 +0100
Subject: [PATCH 28/32] filesystem: add internal xfs struct copy
When the xfs.h header is missing (as these XFS headers are not commonly
installed), instead of completely disabling this functionality,
let's use our internal copy of the basic structure.
Just to cover our 2 needed variables with the ioctl number.
If this would have ever changed - updated is needed...
Prefered use remains to use xfs/xfs.h.
(cherry picked from commit 0774109830d50c5987bb48c877dd5d2f51e406b5)
---
lib/device/filesystem_xfs.c | 38 +++++++++++++++++++++++++------------
1 file changed, 26 insertions(+), 12 deletions(-)
diff --git a/lib/device/filesystem_xfs.c b/lib/device/filesystem_xfs.c
index 61252fe16..a6ab5856d 100644
--- a/lib/device/filesystem_xfs.c
+++ b/lib/device/filesystem_xfs.c
@@ -19,6 +19,31 @@
#include <xfs/xfs.h>
+#else /* !HAVE_XFS_XFS_H */
+
+#include <sys/ioctl.h>
+#include <stdio.h>
+#include <unistd.h>
+
+/* #IOCTL to obtain geometry info */
+#define XFS_IOC_FSGEOMETRY 0x8100587e
+
+/* Copy of some basic and hopefully unchangable XFS header data variables */
+struct xfs_fsop_geom {
+ uint32_t blocksize; /* filesystem (data) block size */
+ uint32_t rtextsize;
+ uint32_t agblocks;
+ uint32_t agcount;
+ uint32_t logblocks;
+ uint32_t sectsize;
+ uint32_t inodesize;
+ uint32_t imaxpct;
+ uint64_t datablocks; /* fsblocks in data subvolume */
+ uint32_t reserved[128]; /* whatever size whole structure may have */
+};
+
+#endif
+
int fs_xfs_update_size_mounted(struct cmd_context *cmd, struct logical_volume *lv,
char *lv_path, struct fs_info *fsi)
{
@@ -40,7 +65,7 @@ int fs_xfs_update_size_mounted(struct cmd_context *cmd, struct logical_volume *l
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",
+ 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:
@@ -48,14 +73,3 @@ out:
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

View File

@ -1,65 +0,0 @@
From b78f20df30d214ab4d7e7f5846e0c3da8c0938ab Mon Sep 17 00:00:00 2001
From: Marian Csontos <mcsontos@redhat.com>
Date: Wed, 7 Jan 2026 11:27:26 +0100
Subject: [PATCH 29/32] autoreconf: reconfigure
---
configure | 20 ++++++++++++++++++++
include/configure.h.in | 3 +++
2 files changed, 23 insertions(+)
diff --git a/configure b/configure
index 935b1b74a..2371dce55 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"
@@ -18237,6 +18251,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 51352c090..8ea936f18 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 <xfs/xfs.h> header file. */
+#undef HAVE_XFS_XFS_H
+
/* Define to 1 if the system has the type '_Bool'. */
#undef HAVE__BOOL
--
2.52.0

View File

@ -1,113 +0,0 @@
From 51e512f9ccc94799cca0810368580da4b263c380 Mon Sep 17 00:00:00 2001
From: David Teigland <teigland@redhat.com>
Date: Thu, 11 Dec 2025 15:52:58 -0600
Subject: [PATCH 30/32] persist: improve setpersist failures
If another host has PR started on a VG, the
vgchange --setpersist command would attempt
to update the VG metadata and fail writing
due to the PR. Handle this case in a more
use-friendly way by checking if another host
has PR started before trying to change the VG
settings.
(cherry picked from commit c19beb55f4691123d5f9606574501f7ef77c697b)
---
lib/device/persist.c | 48 ++++++++++++++++++++++++++++++++++++++++++++
lib/device/persist.h | 1 +
tools/vgchange.c | 8 ++++++++
3 files changed, 57 insertions(+)
diff --git a/lib/device/persist.c b/lib/device/persist.c
index 2b22c8f0a..255c0b1d2 100644
--- a/lib/device/persist.c
+++ b/lib/device/persist.c
@@ -827,6 +827,54 @@ int vg_is_registered(struct cmd_context *cmd, struct volume_group *vg, uint64_t
}
}
+int persist_is_started_by_other_hosts(struct cmd_context *cmd, struct volume_group *vg, int *is_started_other)
+{
+ char our_key_buf[PR_KEY_BUF_SIZE] = { 0 };
+ uint64_t our_key_val = 0;
+ char *local_key = (char *)find_config_tree_str(cmd, local_pr_key_CFG, NULL);
+ int local_host_id = find_config_tree_int(cmd, local_host_id_CFG, NULL);
+ struct pv_list *pvl;
+ struct device *dev;
+ uint64_t *found_keys;
+ int found_local, found_count;
+ int errors = 0;
+
+ if (!get_our_key(cmd, vg, local_key, local_host_id, our_key_buf, &our_key_val))
+ return_0;
+
+ dm_list_iterate_items(pvl, &vg->pvs) {
+ if (!(dev = pvl->pv->dev))
+ continue;
+ if (dm_list_empty(&dev->aliases))
+ continue;
+
+ found_local = 0;
+ found_count = 0;
+ found_keys = NULL;
+
+ if (!dev_find_key(cmd, dev, 1, our_key_val, &found_local, 0, NULL, 1, &found_count, &found_keys)) {
+ log_error("Failed to read persistent reservation key on %s", dev_name(dev));
+ errors++;
+ continue;
+ }
+
+ if (found_keys)
+ dm_pool_free(cmd->mem, found_keys);
+
+ if (found_local && (found_count > 1))
+ *is_started_other = 1;
+
+ if (!found_local && found_count)
+ *is_started_other = 1;
+
+ if (*is_started_other)
+ break;
+ }
+ if (errors)
+ return 0;
+ return 1;
+}
+
int persist_is_started(struct cmd_context *cmd, struct volume_group *vg, int may_fail)
{
struct pv_list *pvl;
diff --git a/lib/device/persist.h b/lib/device/persist.h
index 3792ee580..d4a988bd8 100644
--- a/lib/device/persist.h
+++ b/lib/device/persist.h
@@ -67,6 +67,7 @@ int persist_vgcreate_begin(struct cmd_context *cmd, char *vg_name, char *local_k
int persist_vgcreate_update(struct cmd_context *cmd, struct volume_group *vg, uint32_t set_flags);
int persist_is_started(struct cmd_context *cmd, struct volume_group *vg, int may_fail);
+int persist_is_started_by_other_hosts(struct cmd_context *cmd, struct volume_group *vg, int *is_started_other);
int persist_key_update(struct cmd_context *cmd, struct volume_group *vg, uint32_t prev_gen);
diff --git a/tools/vgchange.c b/tools/vgchange.c
index b701bc54a..06cc8c641 100644
--- a/tools/vgchange.c
+++ b/tools/vgchange.c
@@ -1908,6 +1908,14 @@ static int _vgchange_setpersist_single(struct cmd_context *cmd, const char *vg_n
start_done = 1;
}
+ if (!vg_is_shared(vg) && !start_done) {
+ int yes = 0;
+ if (!persist_is_started_by_other_hosts(cmd, vg, &yes) || yes) {
+ log_error("Cannot change settings while other hosts have PR started.");
+ return ECMD_FAILED;
+ }
+ }
+
if (set_flags & SETPR_Y)
vg->pr = VG_PR_AUTOSTART | VG_PR_REQUIRE;
else if (set_flags & SETPR_N)
--
2.52.0

View File

@ -1,141 +0,0 @@
From e92239ffc00b9b5ea5af84f4c6190f1f2eca4dfe Mon Sep 17 00:00:00 2001
From: Marian Csontos <mcsontos@redhat.com>
Date: Wed, 7 Jan 2026 12:04:03 +0100
Subject: [PATCH 31/32] persist: report error if pr state is not stopped or
started
Co-Authored-By: Claude <noreply@anthropic.com>
(cherrypicked from commit e9bdf7ce740fc575a87f21787f35627970659c08)
---
lib/device/persist.c | 22 ++++++++++++++++------
lib/device/persist.h | 2 +-
lib/metadata/metadata.c | 2 +-
lib/report/report.c | 5 +++--
tools/vgchange.c | 4 ++--
5 files changed, 23 insertions(+), 12 deletions(-)
diff --git a/lib/device/persist.c b/lib/device/persist.c
index 255c0b1d2..98a0b1485 100644
--- a/lib/device/persist.c
+++ b/lib/device/persist.c
@@ -875,18 +875,21 @@ int persist_is_started_by_other_hosts(struct cmd_context *cmd, struct volume_gro
return 1;
}
-int persist_is_started(struct cmd_context *cmd, struct volume_group *vg, int may_fail)
+int persist_is_started(struct cmd_context *cmd, struct volume_group *vg, int *is_error, int may_fail)
{
struct pv_list *pvl;
struct device *dev;
uint64_t our_key_val = 0;
uint64_t holder;
+ int is_stopped = 0;
+ int is_started = 0;
int partial = 0;
int prtype;
- int ret = 0;
- if (!vg_is_registered(cmd, vg, &our_key_val, &partial))
+ if (!vg_is_registered(cmd, vg, &our_key_val, &partial)) {
+ is_stopped = 1;
goto out;
+ }
if (partial) {
log_debug("PR is started: partial");
@@ -923,11 +926,18 @@ int persist_is_started(struct cmd_context *cmd, struct volume_group *vg, int may
goto out;
}
}
- ret = 1;
+
+ is_started = 1;
+
out:
- if (!ret && !may_fail)
+ /* if not started and not stopped, then it's some error condition */
+ if (!is_started && !is_stopped && is_error)
+ *is_error = 1;
+
+ if (!is_started && !may_fail)
log_error("persistent reservation is not started.");
- return ret;
+
+ return is_started;
}
static int get_our_key(struct cmd_context *cmd, struct volume_group *vg,
diff --git a/lib/device/persist.h b/lib/device/persist.h
index d4a988bd8..9ea4f07b7 100644
--- a/lib/device/persist.h
+++ b/lib/device/persist.h
@@ -66,7 +66,7 @@ int persist_vgcreate_begin(struct cmd_context *cmd, char *vg_name, char *local_k
uint32_t set_flags, struct dm_list *devs);
int persist_vgcreate_update(struct cmd_context *cmd, struct volume_group *vg, uint32_t set_flags);
-int persist_is_started(struct cmd_context *cmd, struct volume_group *vg, int may_fail);
+int persist_is_started(struct cmd_context *cmd, struct volume_group *vg, int *is_error, int may_fail);
int persist_is_started_by_other_hosts(struct cmd_context *cmd, struct volume_group *vg, int *is_started_other);
int persist_key_update(struct cmd_context *cmd, struct volume_group *vg, uint32_t prev_gen);
diff --git a/lib/metadata/metadata.c b/lib/metadata/metadata.c
index 06bbc5702..c3e1f55bd 100644
--- a/lib/metadata/metadata.c
+++ b/lib/metadata/metadata.c
@@ -5176,7 +5176,7 @@ struct volume_group *vg_read(struct cmd_context *cmd, const char *vg_name, const
}
if ((vg->pr & VG_PR_REQUIRE) && (writing || activating) && !cmd->disable_pr_required) {
- if (!persist_is_started(cmd, vg, 0)) {
+ if (!persist_is_started(cmd, vg, NULL, 0)) {
failure |= FAILED_PR_REQUIRED;
goto_bad;
}
diff --git a/lib/report/report.c b/lib/report/report.c
index be32e1bb0..8ece9d371 100644
--- a/lib/report/report.c
+++ b/lib/report/report.c
@@ -3025,14 +3025,15 @@ static int _vgprstatus_disp(struct dm_report *rh, struct dm_pool *mem,
{
struct volume_group *vg = (struct volume_group *) data;
struct cmd_context *cmd = (struct cmd_context *) private;
+ int is_error = 0;
if (!vg->pr)
return _field_string(rh, field, "");
- if (persist_is_started(cmd, vg, 1))
+ if (persist_is_started(cmd, vg, &is_error, 1))
return _field_string(rh, field, "started");
else
- return _field_string(rh, field, "stopped");
+ return _field_string(rh, field, is_error ? "error" : "stopped");
}
static int _lvuuid_disp(struct dm_report *rh __attribute__((unused)), struct dm_pool *mem,
diff --git a/tools/vgchange.c b/tools/vgchange.c
index 06cc8c641..bb867b913 100644
--- a/tools/vgchange.c
+++ b/tools/vgchange.c
@@ -713,7 +713,7 @@ do_start:
if (!persist_start_include(cmd, vg, 0, auto_opt, NULL))
return 0;
- if ((vg->pr & (VG_PR_REQUIRE|VG_PR_AUTOSTART)) && !persist_is_started(cmd, vg, 0)) {
+ if ((vg->pr & (VG_PR_REQUIRE|VG_PR_AUTOSTART)) && !persist_is_started(cmd, vg, NULL, 0)) {
log_error("VG %s PR should be started before locking (vgchange --persist start)", vg->name);
return 0;
}
@@ -1890,7 +1890,7 @@ static int _vgchange_setpersist_single(struct cmd_context *cmd, const char *vg_n
* enabling/starting PR, otherwise enabling/starting PR will
* cause i/o to begin failing on those other hosts.
*/
- if (on && vg_is_shared(vg) && !persist_is_started(cmd, vg, 1) &&
+ if (on && vg_is_shared(vg) && !persist_is_started(cmd, vg, NULL, 1) &&
lockd_vg_is_started(cmd, vg, NULL) && lockd_vg_is_busy(cmd, vg)) {
log_error("VG lockspace should be stopped on all hosts (vgchange --lockstop) before enabling PR.");
return ECMD_FAILED;
--
2.52.0

View File

@ -1,27 +0,0 @@
From 8121cf583513b0536a2e70c91dfbdcc451bebc88 Mon Sep 17 00:00:00 2001
From: Zdenek Kabelac <zkabelac@redhat.com>
Date: Sun, 14 Dec 2025 21:54:29 +0100
Subject: [PATCH 32/32] log: add string.h
Header file is using strerror() from <string.h>.
(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 <errno.h>
+#include <string.h>
#define EUNCLASSIFIED -1 /* Generic error code */
--
2.52.0

View File

@ -1,16 +0,0 @@
-----BEGIN PGP SIGNATURE-----
iQIzBAABCAAdFiEE1QGkeEQK4v0TChvouREkMeUJA58FAmj7p+0ACgkQuREkMeUJ
A58LFBAAruvBEXQfdNEkOZ2n0RhtYWLRhV/twkFf9BjUsUdfeYEXQorajfc868Zy
W3lNUrQO/uyxOoNpLxe+mOnXaOSs6dKNbQbCsVsK69r1MXQYkO2+y9RAFyd9VKHA
Oqvu75lB98gWugDOwHop+UovxdEZecXYeATyceQ+Dxhxe7Y/ctIvmd1gF+Fqz58i
BaxBml0QSx2wyIHWeMhWsZ0ToeqAHnBvmUhY6gvZuXLMPU/z7qarzbyiUBbO0PlP
EAcD6ng2r1TAT6aBRUX6/6onwJD3q3EeE9A/yV0Nl9IdfwIoAdMdK6OpVtu5Gr/n
AVIYpqvJWx0JPd/PBuz8D0JAF9O2CQ7BSGkuM+o9FITLRaFKzZza6KK6PT7rLPPs
p+WU87FmMGk9acswP99Zjpcv2d+/vhlAgbXxvR75J2+bMXI6ctqFmKALUs2ms6tl
COJ6150AEef1KrHETyLCX/XV6coanl6l0gT8cp0Fi6hSOoXr34bn8BCGLlvnrL3i
lYbO199vqdRmc2XvHsm6u0Kytzvui1kj9bQU28iylGhjTd69Rr2O6RkzXcZN47CQ
ZlEKOoaocHIXA+eEaHeKK8sJ6zLwiqiwK/kYou5GaA7hKWuIDVer++GHINVsJfIM
FKTNMGg4NXFPnDKdP32ZTG+pAuSupsacGNVVvNA0krBy3s05lb8=
=8WPC
-----END PGP SIGNATURE-----

16
LVM2.2.03.40.tgz.asc Normal file
View File

@ -0,0 +1,16 @@
-----BEGIN PGP SIGNATURE-----
iQIzBAABCgAdFiEE1QGkeEQK4v0TChvouREkMeUJA58FAmnwcpcACgkQuREkMeUJ
A59YTw//cFjY1bW9iPL75j1G3tAW7++7zWEJGi2EB+xEOzaxrlx67hq5Vq/fb+1c
0oOTcszS9Ei4O/U0mHetmicG7D5hlyl/XtVJB9jxt8V9vXE9BRuCIZJLJ947q6Y3
BIoCJdMkXBaz2XoqMHKrB4+0m23zXFbHhfr59BXCyCHd738drzE9RB9CUYSuWKuw
mPfyRmImXgrPWEGRJQo35SBei2ZvIGx7abKkhJVGiaROrZRX9R7toul7o/xOLUgw
s9y6x1FHPDumZ1/37i2r7HP4zm69rjibPiVeitmnT7NDYDq17RYXi5rBZW9Q/P8i
FC/r8GT4tYpbOH1E5r2huNnD3/of7f7JgYiWsoFbhxeMQR+OL2t3kkIBAF0LY41s
XWoV7jUNiSbeDtwo3lpSbDgkZYCfLnYwvvJGLEy+i/LhSIVjAgCKa9cl4TZG4xlK
73HWylPrzP8wWmOAWq583Af2SMR+4STTkec7ahpOn2k0MACFkFsq6ZZREsbLP2Ls
hz7fPQNFc4zdSth/qBGoq7LtGAhHI7uTkqwFjtuZdU/er4da/tzDud4hodkfXTgo
6HzAulmD6GZlChwxU/inzqEyzGfO9j4OlRuszq+ulfcHrWfsG1rPxzrucQc6sxyh
iRUvSo78LsQxtz5GGk9NdcKjYSTiAXzzPUyS32Y7orI1qKeCHNc=
=FyS+
-----END PGP SIGNATURE-----

View File

@ -1,4 +1,4 @@
%global device_mapper_version 1.02.210
%global device_mapper_version 1.02.214
%global enable_cache 1
%global enable_lvmdbusd 1
@ -16,11 +16,9 @@
%global dracut_version 002-18
%global util_linux_version 2.24
%global bash_version 4.0
%global corosync_version 1.99.9-1
%global resource_agents_version 3.9.5-12
%global libselinux_version 1.30.19-4
%global persistent_data_version 0.7.0-0.1.rc6
%global sanlock_version 3.3.0-2
%global sanlock_version 5.1.0-1
%global enable_lockd_sanlock %{enable_lvmlockd}
@ -41,43 +39,12 @@ Name: lvm2
%if 0%{?rhel}
Epoch: %{rhel}
%endif
Version: 2.03.36
Version: 2.03.40
Release: %autorelease
License: GPL-2.0-only
URL: https://sourceware.org/lvm2
Source0: https://sourceware.org/pub/lvm2/releases/LVM2.%{version}.tgz
Patch1: 0001-RHEL10.patch
Patch2: 0002-lvmdbusd-check-DEVLINKS-when-detecting-udev-events.patch
Patch3: 0003-activating-raid-LV-with-partial-snapshot-is-an-error.patch
Patch4: 0004-lv_manip-show-a-warning-during-classic-snapshot-crea.patch
Patch5: 0005-WHATS_NEW-update.patch
Patch6: 0006-cachevol-add-missing-synchronization-with-udev.patch
Patch7: 0007-lvmdbusd-fix-deadlock-on-SIGINT-in-lvm-shell-mode.patch
Patch8: 0008-vdo-add-missing-synchronization.patch
Patch9: 0009-man-update-pvmove-for-pvmove_max_segment_size_mb.patch
Patch10: 0010-lvmpersist-typo-in-PATH.patch
Patch11: 0011-lvmpersist-remove-unregister-error-message.patch
Patch12: 0012-man-keep-page-ascii.patch
Patch13: 0013-man-remove-spaces-at-eol.patch
Patch14: 0014-lvmlockd-vgsplit-is-not-supported.patch
Patch15: 0015-persist-changing-lock-type-should-stop-PR.patch
Patch16: 0016-vgsplit-keep-track-of-the-devices-that-are-moved.patch
Patch17: 0017-vgsplit-update-PR-on-devs-to-match-destination-VG.patch
Patch18: 0018-vgmerge-require-VGs-to-have-the-same-PR-settings.patch
Patch19: 0019-vgimportclone-don-t-use-PR-on-device-being-imported.patch
Patch20: 0020-vgs-add-reporting-field-pr.patch
Patch21: 0021-vgchange-limit-persist-stop-in-lockstop.patch
Patch22: 0022-device_id-prevent-incorrect-dm-uuid-idtype.patch
Patch23: 0023-cache-adding-sync-points.patch
Patch24: 0024-lvmdevices-update-force-option.patch
Patch25: 0025-lvresize-fix-xfs-size-checks.patch
Patch26: 0026-configure-check-for-xfs-header-file.patch
Patch27: 0027-filesystem-refactor-code-working-with-xfs.patch
Patch28: 0028-filesystem-add-internal-xfs-struct-copy.patch
Patch29: 0029-autoreconf-reconfigure.patch
Patch30: 0030-persist-improve-setpersist-failures.patch
Patch31: 0031-persist-report-error-if-pr-state-is-not-stopped-or-s.patch
Patch32: 0032-log-add-string.h.patch
BuildRequires: make
BuildRequires: gcc
@ -86,6 +53,7 @@ BuildRequires: gcc-c++
%endif
BuildRequires: libselinux-devel >= %{libselinux_version}, libsepol-devel
BuildRequires: libblkid-devel >= %{util_linux_version}
BuildRequires: xfsprogs-devel
BuildRequires: ncurses-devel
BuildRequires: libedit-devel
BuildRequires: libaio-devel
@ -111,7 +79,7 @@ Requires: %{name}-libs = %{?epoch}:%{version}-%{release}
Requires(post): (system-release >= %{system_release_version} if system-release)
%endif
Requires: bash >= %{bash_version}
Requires(post): systemd-units >= %{systemd_version}, systemd-sysv
Requires(post): systemd-units >= %{systemd_version}
Requires(preun): systemd-units >= %{systemd_version}
Requires(postun): systemd-units >= %{systemd_version}
Requires: module-init-tools
@ -303,6 +271,9 @@ systemctl start lvm2-lvmpolld.socket >/dev/null 2>&1 || :
%{_sbindir}/vgsplit
%attr(755, -, -) %{_libexecdir}/lvresize_fs_helper
%{_mandir}/man5/lvm.conf.5.gz
%{_mandir}/man7/lvm-args.7.gz
%{_mandir}/man7/lvm-categories.7.gz
%{_mandir}/man7/lvm-index.7.gz
%{_mandir}/man7/lvmautoactivation.7.gz
%{_mandir}/man7/lvmcache.7.gz
%{_mandir}/man7/lvmraid.7.gz
@ -556,8 +527,10 @@ for the kernel device-mapper.
%{_sbindir}/dmsetup
%{_sbindir}/blkdeactivate
%{_sbindir}/dmstats
%{_sbindir}/dmvdostats
%{_mandir}/man8/dmsetup.8.gz
%{_mandir}/man8/dmstats.8.gz
%{_mandir}/man8/dmvdostats.8.gz
%{_mandir}/man8/blkdeactivate.8.gz
%if %{enable_dmfilemapd}
%{_sbindir}/dmfilemapd
@ -682,6 +655,10 @@ An extensive functional testsuite for LVM2.
%endif
%changelog
* Tue Apr 28 2026 Marian Csontos <mcsontos@redhat.com> - 2.03.40-1
- Update to upstream version 2.03.40.
- See WHATS_NEW and WHATS_NEW_DM for more information.
* Wed Jan 07 2026 Marian Csontos <mcsontos@redhat.com> - 2.03.36-2
- Additional fixes up to 2.03.38.

View File

@ -1 +1 @@
SHA512 (LVM2.2.03.36.tgz) = bc70dbe9e099c2fa63333dfd355bdd0c5493f6554a3d17689d5180546433165225c718e9cf227b0a1f6b835cc6ceb6e02e500c79badb13174985e604ad093389
SHA512 (LVM2.2.03.40.tgz) = 115712f16c5fc5f2dce04efc9b42f803101dc1ef99deaed4e769852e87b89cbfa1817efc583978cd3a4ed0f5a34420bb688894f24e7a6cd409f78248c53c5214

View File

@ -1 +1 @@
LVM2.2.03.36.tgz
LVM2.2.03.40.tgz