import CS lvm2-2.03.33-4.el9

This commit is contained in:
AlmaLinux RelEng Bot 2026-03-30 10:44:19 -04:00
parent 14d381d8bb
commit b5e43fdc08
67 changed files with 4743 additions and 931 deletions

2
.gitignore vendored
View File

@ -1 +1 @@
SOURCES/LVM2.2.03.32.tgz
SOURCES/LVM2.2.03.33.tgz

View File

@ -1 +1 @@
6b0df2dddc2ee883380969362f5e5d1e89a6960d SOURCES/LVM2.2.03.32.tgz
63bb26807fa2dc9b8df29525bd854335a278eed5 SOURCES/LVM2.2.03.33.tgz

View File

@ -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 <mcsontos@redhat.com>
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

View File

@ -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 <mcsontos@redhat.com>
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

View File

@ -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 <mcsontos@redhat.com>
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

View File

@ -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 <mcsontos@redhat.com>
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

View File

@ -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 <mcsontos@redhat.com>
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

View File

@ -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 <mcsontos@redhat.com>
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

View File

@ -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 <mcsontos@redhat.com>
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

View File

@ -1,143 +0,0 @@
From 54d5564f0fc375278c940635c449bdeb24334b71 Mon Sep 17 00:00:00 2001
From: David Teigland <teigland@redhat.com>
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

View File

@ -0,0 +1,50 @@
From 8920f236abae6a9e7b15a0b11c1b9d5bad370aae Mon Sep 17 00:00:00 2001
From: David Teigland <teigland@redhat.com>
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

View File

@ -0,0 +1,686 @@
From 5878a6dc3167e4f9fc4c1dcb04c3dd41e3d4db19 Mon Sep 17 00:00:00 2001
From: David Teigland <teigland@redhat.com>
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, &sector_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, &sector_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

View File

@ -1,38 +0,0 @@
From 0b375ab5f49c4eea0c705ef8e27e94a366b0f6d6 Mon Sep 17 00:00:00 2001
From: David Teigland <teigland@redhat.com>
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

View File

@ -1,460 +0,0 @@
From ad632cf9f19f3b8efbcf087cbf60527160ba5fec Mon Sep 17 00:00:00 2001
From: Heinz Mauelshagen <heinzm@redhat.com>
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 <inttypes.h>
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 <fcntl.h>
+#include <unistd.h>
+
+/* 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 <stdint.h>
+
+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

View File

@ -0,0 +1,54 @@
From 4659eb9d2a7b58a9b199d7cf2ccaaf32d6605a76 Mon Sep 17 00:00:00 2001
From: Peter Rajnoha <prajnoha@redhat.com>
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

View File

@ -0,0 +1,81 @@
From 6ca7cd60fd6afcc0f95dfe20d33044a319621b6d Mon Sep 17 00:00:00 2001
From: Peter Rajnoha <prajnoha@redhat.com>
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

View File

@ -1,64 +0,0 @@
From 4fbda3d36dc02bb682dd8579c8a4ebfc692cbfe3 Mon Sep 17 00:00:00 2001
From: Zdenek Kabelac <zkabelac@redhat.com>
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

View File

@ -0,0 +1,32 @@
From 6d7837dc2b93a51bfdad7c796d2b8e3f7fe9f938 Mon Sep 17 00:00:00 2001
From: Peter Rajnoha <prajnoha@redhat.com>
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

View File

@ -1,107 +0,0 @@
From 7ef2e32ab91194abfcacb96eae2577cf19e66123 Mon Sep 17 00:00:00 2001
From: Zdenek Kabelac <zkabelac@redhat.com>
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

View File

@ -0,0 +1,48 @@
From f697518550298ec4a571b72f0f6395b42e6fc85d Mon Sep 17 00:00:00 2001
From: Peter Rajnoha <prajnoha@redhat.com>
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

View File

@ -1,50 +0,0 @@
From 63312cb3343d6370c89ab0ff4e93aa39aab25fa5 Mon Sep 17 00:00:00 2001
From: Zdenek Kabelac <zkabelac@redhat.com>
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

View File

@ -1,25 +1,24 @@
From 14f920c81c9499bcfcc0414c494f7abc0b9f3d58 Mon Sep 17 00:00:00 2001
From: Zdenek Kabelac <zkabelac@redhat.com>
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 <prajnoha@redhat.com>
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

View File

@ -0,0 +1,103 @@
From cc809a01ac3059fa613473ce45bc75426ab000ad Mon Sep 17 00:00:00 2001
From: Peter Rajnoha <prajnoha@redhat.com>
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

View File

@ -0,0 +1,97 @@
From e845c1a99d660295735d6fd0dd5a048f3980fce7 Mon Sep 17 00:00:00 2001
From: Peter Rajnoha <prajnoha@redhat.com>
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

View File

@ -0,0 +1,56 @@
From 5653b3e38962d81264dd45db1aad356f6f59dd6c Mon Sep 17 00:00:00 2001
From: David Teigland <teigland@redhat.com>
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

View File

@ -0,0 +1,26 @@
From a70dd84cfdd897a8b9d8cdddd98caaacaa1dff72 Mon Sep 17 00:00:00 2001
From: Zdenek Kabelac <zkabelac@redhat.com>
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

View File

@ -0,0 +1,28 @@
From de5bc8c70577b3d7483c43ce373d233d9089a990 Mon Sep 17 00:00:00 2001
From: David Teigland <teigland@redhat.com>
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

View File

@ -0,0 +1,33 @@
From 20b81f31c29f416a9c397e41d6998b10fc379228 Mon Sep 17 00:00:00 2001
From: David Teigland <teigland@redhat.com>
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

View File

@ -0,0 +1,27 @@
From d4406030d3fcaa9286fa9ef86fe4ebed04303bbf Mon Sep 17 00:00:00 2001
From: David Teigland <teigland@redhat.com>
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

View File

@ -0,0 +1,57 @@
From 2477a95fe1a47ff4e8c4c8afda7c4b95dddfaeda Mon Sep 17 00:00:00 2001
From: David Teigland <teigland@redhat.com>
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

View File

@ -0,0 +1,582 @@
From e193db35a368dcd9ac8c9737d774d3552d4cf877 Mon Sep 17 00:00:00 2001
From: David Teigland <teigland@redhat.com>
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 <vgname> <devices>
.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 <vgname> 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 <vgname>
+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 <vgname> \&.\|.\|.
-.br
-vgchange --lockstop <vgname> \&.\|.\|.
-.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

View File

@ -0,0 +1,44 @@
From 1fee1b03564bb807e7adedefb27180babcd861d0 Mon Sep 17 00:00:00 2001
From: Zdenek Kabelac <zkabelac@redhat.com>
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

View File

@ -0,0 +1,113 @@
From 20a049ac3267240de7ffcfb55cf58c08fe7d88a6 Mon Sep 17 00:00:00 2001
From: Zdenek Kabelac <zkabelac@redhat.com>
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

View File

@ -0,0 +1,41 @@
From c25e62f4e0532dfb55e2c81a6e236edfeffa8c11 Mon Sep 17 00:00:00 2001
From: Zdenek Kabelac <zkabelac@redhat.com>
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

View File

@ -0,0 +1,65 @@
From fa4c75d8e20019a11c722d1cc7f3923b3e4b5324 Mon Sep 17 00:00:00 2001
From: Zdenek Kabelac <zkabelac@redhat.com>
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

View File

@ -0,0 +1,39 @@
From 15164d1c1f84cd583e93b13e277f4cbae310b03b Mon Sep 17 00:00:00 2001
From: Zdenek Kabelac <zkabelac@redhat.com>
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

View File

@ -0,0 +1,44 @@
From b2814746de3fac6809c07dbd74ca606388a57aa8 Mon Sep 17 00:00:00 2001
From: Zdenek Kabelac <zkabelac@redhat.com>
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

View File

@ -0,0 +1,47 @@
From 51f6e02a458f763d4066782549f0b3873317119d Mon Sep 17 00:00:00 2001
From: Zdenek Kabelac <zkabelac@redhat.com>
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

View File

@ -0,0 +1,34 @@
From 940d475e612a8ae2e3fe48213e7ed2a5c2a40705 Mon Sep 17 00:00:00 2001
From: Zdenek Kabelac <zkabelac@redhat.com>
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

View File

@ -0,0 +1,54 @@
From ceb2cbb8a9252222e24d919977b149a5f455c11c Mon Sep 17 00:00:00 2001
From: Zdenek Kabelac <zkabelac@redhat.com>
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

View File

@ -0,0 +1,61 @@
From 659e03ed04eff50f12d56baff949d1e7e7b3168b Mon Sep 17 00:00:00 2001
From: Zdenek Kabelac <zkabelac@redhat.com>
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

View File

@ -0,0 +1,35 @@
From 6596b120d33f33286f37ba8b2f486fa01978b82e Mon Sep 17 00:00:00 2001
From: Zdenek Kabelac <zkabelac@redhat.com>
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

View File

@ -0,0 +1,33 @@
From e10a604ae404ff6a87eced54743d5a539a06a030 Mon Sep 17 00:00:00 2001
From: Zdenek Kabelac <zkabelac@redhat.com>
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

View File

@ -0,0 +1,30 @@
From bf48c1541291aeda537520b664f59249fc85f95b Mon Sep 17 00:00:00 2001
From: Zdenek Kabelac <zkabelac@redhat.com>
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

View File

@ -0,0 +1,30 @@
From 7f5a4a9de4aab40f2c243f0f657008da839cb75f Mon Sep 17 00:00:00 2001
From: Zdenek Kabelac <zkabelac@redhat.com>
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

View File

@ -0,0 +1,39 @@
From 89300351f254ce1fe499f6bae609c16a0b1ef60a Mon Sep 17 00:00:00 2001
From: Zdenek Kabelac <zkabelac@redhat.com>
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

View File

@ -0,0 +1,40 @@
From 4ed321be7a9dcd3df99f3175f03bc45d65989c98 Mon Sep 17 00:00:00 2001
From: Zdenek Kabelac <zkabelac@redhat.com>
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

View File

@ -0,0 +1,53 @@
From a7c707334f3b2d571f8fa80db75e631b11e4b09b Mon Sep 17 00:00:00 2001
From: Zdenek Kabelac <zkabelac@redhat.com>
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

View File

@ -0,0 +1,37 @@
From d825680fd9fae523f166a1ff1a833e5157ccce79 Mon Sep 17 00:00:00 2001
From: Zdenek Kabelac <zkabelac@redhat.com>
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

View File

@ -0,0 +1,58 @@
From 5af9f7beca2c30815707c412dcbe31a109fd0d62 Mon Sep 17 00:00:00 2001
From: Peter Rajnoha <prajnoha@redhat.com>
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

View File

@ -0,0 +1,88 @@
From 147d05c177c39d298f02fc6f786e476308413133 Mon Sep 17 00:00:00 2001
From: Peter Rajnoha <prajnoha@redhat.com>
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

View File

@ -0,0 +1,51 @@
From c370fe563dd095a09f6e070afb8a5c8e4915ec47 Mon Sep 17 00:00:00 2001
From: David Teigland <teigland@redhat.com>
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

View File

@ -0,0 +1,51 @@
From 85a712e95a5c0127d27ca3bbbe7019d54393cc33 Mon Sep 17 00:00:00 2001
From: Peter Rajnoha <prajnoha@redhat.com>
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

View File

@ -0,0 +1,28 @@
From dcae883b382f03a58a04d72f6a3bb446e4814ae9 Mon Sep 17 00:00:00 2001
From: Peter Rajnoha <prajnoha@redhat.com>
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

View File

@ -0,0 +1,162 @@
From 3a6c6366c0605fbb7b0001d920da6bd801bff689 Mon Sep 17 00:00:00 2001
From: Marian Csontos <mcsontos@redhat.com>
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

View File

@ -0,0 +1,48 @@
From 52efa6f5a1a5a9057130d0b3c8acfdb8feff2e22 Mon Sep 17 00:00:00 2001
From: David Teigland <teigland@redhat.com>
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

View File

@ -0,0 +1,34 @@
From a71342640ddf81b73625e55149f1077245ee7412 Mon Sep 17 00:00:00 2001
From: Heinz Mauelshagen <heinzm@redhat.com>
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

View File

@ -0,0 +1,67 @@
From 4ad6776b11103a864b98963c3540e87e13db2450 Mon Sep 17 00:00:00 2001
From: Heinz Mauelshagen <heinzm@redhat.com>
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

View File

@ -0,0 +1,36 @@
From 8af5d6dda5a1e29e0fa9e573ca6f6cf69d07aa9b Mon Sep 17 00:00:00 2001
From: Heinz Mauelshagen <heinzm@redhat.com>
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

View File

@ -0,0 +1,240 @@
From 48c68c0cc2cef75f6aa1c6a3e68c44b3a806f60a Mon Sep 17 00:00:00 2001
From: David Teigland <teigland@redhat.com>
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

View File

@ -0,0 +1,350 @@
From dcda3b48c2f6ca9841d53911d10fe8825f4e1d19 Mon Sep 17 00:00:00 2001
From: David Teigland <teigland@redhat.com>
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 <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 *_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

View File

@ -0,0 +1,37 @@
From f533eab471f78f27c86d9b88cf2ba66df924f3ea Mon Sep 17 00:00:00 2001
From: Zdenek Kabelac <zkabelac@redhat.com>
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

View File

@ -0,0 +1,27 @@
From 9248e4fa05534a0865a7fad4b0bb76ca85c4dd55 Mon Sep 17 00:00:00 2001
From: Zdenek Kabelac <zkabelac@redhat.com>
Date: Sun, 14 Dec 2025 21:54:29 +0100
Subject: [PATCH 55/57] 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

@ -0,0 +1,208 @@
From 077eaef48b2d257e94feb1caa3825fa5a5da14e6 Mon Sep 17 00:00:00 2001
From: Zdenek Kabelac <zkabelac@redhat.com>
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 <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 *_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 <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

@ -0,0 +1,210 @@
From 86812cc39d76f615af43d165c0117cae0c844129 Mon Sep 17 00:00:00 2001
From: Zdenek Kabelac <zkabelac@redhat.com>
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 <stdint.h>
#include <fcntl.h>
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 <assert.h>
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

View File

@ -0,0 +1,113 @@
From 5c44e8301451e0bace56c5f1400f11f4758d2aed Mon Sep 17 00:00:00 2001
From: Zdenek Kabelac <zkabelac@redhat.com>
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 <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,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 <mcsontos@redhat.com> - 2.03.33-4
- Handle wrong XFS reported size when shrinking LV immediately after growing.
* Tue Jan 06 2026 Marian Csontos <mcsontos@redhat.com> - 2.03.33-3
- Allow integrity to use multiple segments for metadata.
* Mon Nov 10 2025 Marian Csontos <mcsontos@redhat.com> - 2.03.33-2
- Add message when activating RAID volumes with snapshots.
* Mon Sep 29 2025 Marian Csontos <mcsontos@redhat.com> - 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 <mcsontos@redhat.com> - 2.03.32-2
- Fix vgremove hanging immediately after lockstart.
- Add repair option for RAID volumes with too many transiently failed devices.